レスポンシブルにフォントサイズを変更するための SASS Mixin を作った

2022-04-14 : 最近は clamp() という便利な CSS 関数があるので、ページ幅などをメディアクエリで細かく指定したい場合を除けば clamp() 関数で実装するのが楽です。

以前紹介した、レスポンシブルにフォントサイズを変更するための CSS。

計算式が複雑で使い回すのが大変だったので、SASS のミックスインとして作ってみた。

引数から単位を除去して数値のみにしたかったので、その部分を strip-unit() 関数として用意した。SASS って @if とか使えるのね…。

/// 引数に単位が付いている場合は単位を除去して数値のみ返却する
/// 
/// @param $num {number} 数値のみ返却してほしい値
/// @return {number} 引数を数値のみに変換した値
@function strip-unit($num) {
  @if type-of($num) == 'number' and not unitless($num) {
    @return $num / ($num * 0 + 1);
  }
  
  @return $num;
}

/// 単位がない数値に px を付ける
/// 
/// @param $num {number} 単位のみの値
/// @return {number} 引数を px 単位に変換した値
@function to-px($num) {
  @return $num * 1px;
}

/// レスポンシブルにフォントサイズを変更する
/// 
/// @param {number} $min-font-size 最小フォントサイズ (px)
/// @param {number} $max-font-size 最大フォントサイズ (px)
/// @param {number} $min-breakpoint 最小ビューポート幅 (px)
/// @param {number} $max-breakpoint 最大ビューポート幅 (px)
/// @param {number} $root-font-size ルートのフォントサイズ・未指定時は 16 (px)
@mixin responsive-font-size($min-font-size, $max-font-size, $min-breakpoint, $max-breakpoint, $root-font-size: 16px) {
  $min-font-size-num : strip-unit($min-font-size);
  $max-font-size-num : strip-unit($max-font-size);
  $min-breakpoint-num: strip-unit($min-breakpoint);
  $max-breakpoint-num: strip-unit($max-breakpoint);
  $root-font-size-num: strip-unit($root-font-size);
  
  // Min Font Size
  font-size: to-px($min-font-size-num);
  
  // Responsive Font Size
  @media (min-width: to-px($min-breakpoint-num)) {
    $min-font-size-rem        : ($min-font-size-num / $root-font-size-num * 1rem);
    $min-breakpoint-percent-px: ($min-breakpoint-num / 100 * 1px);
    $font-size-difference     : ($max-font-size-num - $min-font-size-num);
    $breakpoint-difference    : ($max-breakpoint-num - $min-breakpoint-num);
    $differences              : (100 * $font-size-difference / $breakpoint-difference);
    
    font-size: calc( #{$min-font-size-rem} + ( 1vw - #{$min-breakpoint-percent-px} ) * #{$differences} );
  }
  
  // Max Font Size
  @media (min-width: to-px($max-breakpoint-num)) {
    font-size: to-px($max-font-size-num);
  }
}

コメントは SassDoc 形式にしてみた。

使う時はこんな感じ。引数には単位 px を付けても付けなくても良い。

// SCSS
html {
  // 16px @ 768px から 24px @ 1024px に変更する (ルートのフォントサイズは未指定で 16px として扱わせる)
  @include responsive-font-size(18px, 24px, 768px, 1024px);
}

これがコンパイルされると、以下のようになる。

/* CSS */
html {
  font-size: 16px;
}
@media (min-width: 768px) {
  html {
    font-size: calc( 1rem + ( 1vw - 7.68px ) * 3.125);
  }
}
@media (min-width: 1024px) {
  html {
    font-size: 24px;
  }
}

以下のサイトのジェネレータで生成できるのと同じ状態にできただろう。

strip-unit() 関数については以下の記事のコードを利用。

以下にサンプルを置いてみたので、実際の動作を試してみてほしい。

以上。