0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【画面比率ですべて伸縮】レスポンシブを@mixinと@functionで簡単に実現する

Last updated at Posted at 2024-07-17

レスポンシブデザインにおいて、デザインされたアートボードサイズ以外のレイアウトをどうすればよいか、デザイナーとコーダーのよくある問題だと思います。

デザインするときにそこまで考慮していたら単調なデザインになるし、苦労してコーディング終わらせてから想定外なフィードバックが返ってきたり...

レスポンシブのための便利な@mixin@functionを考える

開発者目線ですが、体感的にデザイナーはデザインしたサイズ感でwindow.widthに合わせて伸縮するのを好む傾向にあると思います。
ですので、デザインのサイズ感を極力遵守する形でレスポンシブを実現できる便利な@mixin@functionを考えてみたいと思います。

実現したいこと

レスポンシブ

  • window.widthに対して各要素のアスペクト比を保って伸縮したい。
  • 一定のwindow.width以上は伸縮をさせないように上限を設ける。
  • 伸縮させるとどうしてもデザインが破綻する場合があるので、最小値・最大値を考慮する。
  • stylelintのCSSプロパティソートの邪魔をしない。

こちらは別の機会に...

  • font-sizeもいい感じに伸縮したい。
    • ブラウザは10px未満のfont-sizeをデフォルトでは描画しない(強制的に10pxになる)ので、font-sizeの減縮には限度があることを考慮する。

デザインデータ

通常Tabletのデザインまで用意することは少ないですが、デザインによってはTabletでブレークポイントを設けたいケースもあると思います。
そこで今回はSP、Tablet、Desktopの3パターンのブレークポイントを設ける形で考えます。

デバイス アートボードサイズ
SP 375px
Tablet 768px
Desktop 1600px

※ 1600px以上はコンテンツブロックをセンタリングする想定

全容

$device: 0px;
$mobile: 375px;
$tablet: 768px;
$desktopS: 1024px;
$desktop: 1600px;

@mixin onlyTablet {
  @media only screen and (min-width: $tablet) and (max-width: $desktopS) {
    $device: $tablet !global;
    @content;
    $device: 0px !global;
  }
}

@mixin onlyDesktop {
  @media only screen and (min-width: $desktopS + 1px) {
    $device: $desktopS !global;
    @content;
    $device: 0px !global;
  }
}

@function vw($px) {
  @if $device == $desktopS {
    @return clamp(calc($desktopS / $desktop * $px), calc($px / $desktop * 100vw), $px);
  }
  @else if $device == $tablet {
    @return clamp($px, calc($px / $tablet * 100vw), calc($desktopS / $tablet * $px));
  }

  @return clamp($px, calc($px / $mobile * 100vw), calc($tablet / $mobile * $px));
}


.hogehoge {
  padding-top: vw(20px);

  @include onlyTablet {
    padding-top: vw(60px);
  }

  @include onlyDesktop {
    padding-top: vw(120px);
  }
}

コンパイル結果

.hogehoge {
  padding-top: clamp(20px, 5.3333333333vw, 40.96px);
}
@media only screen and (min-width: 768px) and (max-width: 1024px) {
  .hogehoge {
    padding-top: clamp(60px, 7.8125vw, 80px);
  }
}
@media only screen and (min-width: 1025px) {
  .hogehoge {
    padding-top: clamp(76.8px, 7.5vw, 120px);
  }
}

定数

各ブレークポイントを定数化しておくことで、後々の変更に耐えられる作りにします。
$deviceには後述の!globalフラグによってdevice状態が入ってきます。

$device: 0px; // デバイスの振り分け状態を格納するグローバル変数
$mobile: 375px; // SPのデザインデータサイズ
$tablet: 768px; // Tablet下限ブレークポイント
$desktopS: 1024px; // Tablet上限、Desktopの下限ブレークポイント
$desktop: 1600px; // Desktop上限ブレークポイント

mixin

メディアクエリmixinを定義。
ポイントは!globalフラグでグローバル変数として定義してある$deviceに状態を一時保存する部分です。
また、Content Blocksでの処理が終わったら改めて$deviceを初期値に戻してあげる必要があります。

@mixin onlyTablet {
  // @media only screen and (min-width: 768px) and (max-width: 1024px) {
  @media only screen and (min-width: $tablet) and (max-width: $desktopS) {
    // $device: 768px !global;
    $device: $tablet !global;
    @content;
    $device: 0px !global;
  }
}

@mixin onlyDesktop {
  // @media only screen and (min-width: 1024px + 1px) {
  @media only screen and (min-width: $desktopS + 1px) {
    // $device: 1024px !global;
    $device: $desktopS !global;
    @content;
    $device: 0px !global;
  }
}

!globalフラグ

If you need to set a global variable’s value from within a local scope (such as in a mixin), you can use the !global flag. A variable declaration flagged as !global will always assign to the global scope.

ローカルスコープからグローバル変数の値を設定する必要がある場合(ミックスインなど)、!globalフラグを使うことができる。!globalフラグが付いた変数宣言は、常にグローバルスコープに代入されます。

SASSドキュメント - Variables - ScopeScope

function

$deviceで渡された引数によって、SP、Tablet、Desktopのそれぞれの最小値・推奨値・最大値を算出し、clamp関数を返却します。

@function vw($px) {
  @if $device == $desktopS {
    // clamp(calc(1024px / 1600px * 120px), calc(120px / 1600px * 100vw), 120px);
    // => clamp(76.8px, 7.5vw, 120px);
    @return clamp(calc($desktopS / $desktop * $px), calc($px / $desktop * 100vw), $px);
  }
  @else if $device == $tablet {
    // clamp(60px, calc(60px / 768px * 100vw), calc(1024px / 768px * 60px));
    // => clamp(60px, 7.8125vw, 80px);
    @return clamp($px, calc($px / $tablet * 100vw), calc($desktopS / $tablet * $px));
  }

  // clamp(20px, calc(20px / 375px * 100vw), calc(768px / 375px * 20px));
  // => clamp(20px, 5.3333333333vw, 40.96px);
  @return clamp($px, calc($px / $mobile * 100vw), calc($tablet / $mobile * $px));
}

SPの場合

// clamp(20px, calc(20px / 375px * 100vw), calc(768px / 375px * 20px));
// => clamp(20px, 5.3333333333vw, 40.96px);
@return clamp($px, calc($px / $mobile * 100vw), calc($tablet / $mobile * $px));

最小値
 指定した20px。

推奨値
 20pxと基準サイズの375pxの比率を算出し、100vwを掛けることで画面幅に対する数値をvwで得ることができる。

最大値
Tablet最小値の768pxまで伸縮するため、$tablet / $mobileで拡大率を算出し、20pxに掛けることで768pxまで大きくした場合の数値を得ることができる。

Tabletの場合

// clamp(60px, calc(60px / 768px * 100vw), calc(1024px / 768px * 60px));
// => clamp(60px, 7.8125vw, 80px);
@return clamp($px, calc($px / $tablet * 100vw), calc($desktopS / $tablet * $px));

最小値
 指定した60px。

推奨値
 60pxと基準サイズの768pxの比率を算出し、100vwを掛けることで画面幅に対する数値をvwで得ることができる。

最大値
Desktop最小値の1024pxまで伸縮するため、$desktopS / $tabletで拡大率を算出し、60pxに掛けることで1024pxまで大きくした場合の数値を得ることができる。

Desktopの場合

// clamp(calc(1024px / 1600px * 120px), calc(120px / 1600px * 100vw), 120px);
// => clamp(76.8px, 7.5vw, 120px);
@return clamp(calc($desktopS / $desktop * $px), calc($px / $desktop * 100vw), $px);

最小値
Desktop最小値の1024pxまで伸縮するため、$desktopS / $desktopで縮小率を算出し、120pxに掛けることで1024pxまで小さくした場合の数値を得ることができる。

推奨値
 120pxと基準サイズの1600pxの比率を算出し、100vwを掛けることで画面幅に対する数値をvwで得ることができる。

最大値
 指定した120px。

CSS

padding-topなどプロパティ名は通常通り書くことでstylelintの邪魔をせずにプロパティの並び順などを統一化できます。
また、function名はシンプルにvw()とし、SP、Tablet、Desktopで統一したfunctionの呼び方ができるようにすることで、VS Codeのスニペットにも登録しやすくしています。

.hogehoge {
  padding-top: vw(20px);

  @include onlyTablet {
    padding-top: vw(60px);
  }

  @include onlyDesktop {
    padding-top: vw(120px);
  }
}

こんな感じに書くとプロパティ名でソートされず(@includeでソートされてしまう)、プロパティ名の並び順を自動で統一できない。

.hogehoge {
  @include vw(padding-top, 20px, 60px, 120px);
}

参考

SASS ドキュメント
現場で役立つ実践Sass(3)変数を使いこなす

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?