0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

レスポンシブのときfont-sizeを可変対応させるCSS/SCSS

Last updated at Posted at 2021-07-05

レスポンシブサイトでするっと可変するfont-size

最近はハードが増えたので、メディアクエリで区切るとクライアントさんに怒られる。
うっかり1行でも増えようものなら、デザイナーさんが「デザインと違う」と嘆く。
特にタブレットカンプがないときの「いい感じになるよう頼みます」は厄介だ。いい感じとは?

CSSでcalcが使えるようになったおかげでvwの使い勝手は大変良いが、可変域が広いと面倒だ。
算数はできない。数学なんてもってのほかだ。
とはいえ人並みの国語力はある。字は読める。数字も多分読めているはずだ。
もっと直感的に処理したい。せめてSPとPCのカンプデータがあればあとは機械にお任せにしたい。

と思ってgoogle先生に聞いてみたら、頭の良い人親切な人がたくさんいた。すごい。

連立方程式と一時関数

下記のグラフがとてもわかりやすかった。

CSSだけでレスポンシブ対応 font-sizeを画面に合わせて自動で変える

参考サイトによると、PC時の値とSP時の値で連立方程式とつくって、xとyの値を一次関数の式にはめこめばよいとのこと。
なるほど...?SPのwidthとfont-sizeを「最小値」、PCのwidthとfont-sizeを「最大値」に設定して、両者をむすぶ直線上の値を求める。これをcalcに計算してもらえばいいわけだ。
計算式はこちらを参考にして、あとは計算できれば...!

JavaScript

SCSSもなんとかしたいが、使わない案件もある。とりあえずJSで適当な計算機をつくってみることに。
SCSSでfunctionつくるとき役立つかもしれないし。(「プロパティ名が見やすい」というお馬鹿で単純な理由からfunctionが好きだ。この時はまだ穴にはまったことに気が付いていない。)

デモ

Calc.js
// all
const values = document.querySelectorAll('input');
// sp
const spWidth = document.getElementById('js-spWidth');
const spFontSize = document.getElementById('js-spFontSize');
// pc
const pcWidth = document.getElementById('js-pcWidth');
const pcFontSize = document.getElementById('js-pcFontSize');
const sendBtn = document.getElementById('send');

// result
const viewElm = document.getElementById('result');

// 四捨五入用
function round(number, base) {
  const pow = Math.pow(10, base);
  return Math.round(number * pow) / pow;
}
sendBtn.onclick = () => {
  // リセット
  viewElm.textContent = '';

  // 空判定
  let nullValues = 0;
  for (let i = 0; i < values.length; i++) {
    const value = values[i].value;
    if (!value) {
      nullValues++;
    }
  }
  if (nullValues != 0) {
    window.alert('未入力項目があります。');
    return;
  }

  // 計算
  const spWidthNum = Number(spWidth.value);
  const spFontSizeNum = Number(spFontSize.value);
  const pcWidthNum = Number(pcWidth.value);
  const pcFontSizeNum = Number(pcFontSize.value);
  const x = pcFontSizeNum - spFontSizeNum;
  let y;
  let result;
  if ( x != 0 ) {
    y = (pcWidthNum - spWidthNum) / x;
    // 小数点以下4桁で四捨五入
    y = round(y, 4);
    result = 'font-size: calc(((100vw - ' + spWidthNum + 'px) / ' + y + ') + ' + spFontSizeNum + 'px);';
  } else {
    result = spFontSizeNum + 'px';
  }

  // 表示
  const p = document.createElement('p');
  const viewTxt= p.appendChild(document.createTextNode(result));
  viewElm.appendChild(viewTxt);
};
sample.html
  <form action="post">
    <h2>SP</h2>
    <p>SP表示時の画面幅とfont-sizeを入力してください。</p>
    <p><label for="js-spWidth">SP:width</label>
    <input type="number" id="js-spWidth" name="spWidth" min="0" max="10000"> px</p>
    <p><label for="js-spFontSize">SP:font-size</label>
    <input type="number" id="js-spFontSize" name="spFontSize" min="0" max="1000"> px</p>
    <h2>PC</h2>
    <p>PC表示時の画面幅とfont-sizeを入力してください。</p>
    <p><label for="js-pcWidth">PC:width</label>
    <input type="number" id="js-pcWidth" name="pcWidth" min="0" max="10000"> px</p>
    <p><label for="js-pcFontSize">SP:font-size</label>
    <input type="number" id="js-pcFontSize" name="pcFontSize" min="0" max="1000"> px</p>
    <button type="button" id="send">送信</button>
  </form>
  <div class="section__result" id="result"></div>

四捨五入

あまり小数点以下が長いと疲れる。4桁でカットする。だいたいInt型しか使わないので四捨五入の方法に困った。
CSSコピペるとき0埋めがなんとなくいやという理由でtoFixed()を使っていない。
処理速度考えたら使った方がいいのかな?いやローカルでしか使わんしな。好きにする。

条件分岐

font-sizeが0のときは計算ができない。0の除算はできないわけで、JSではInfinityがでる。
そもそも意味がないのでif文で0以外のときに限定する。SPとPCのfont-sizeが同じ数値の時と同様elseにつっこむ。
SPとPCのfont-sizeが同じということはつまり可変じゃなくて固定値な訳だから、SPのvalueをそのまま出力する。

SCSS

とりあえずなんとなくわかってきたような気がする。
SCSSで変数指定して使えるようにしよう。

しかしfunctionでエラーになる。なぜだ。基本的に単位が異なる数値は計算できないからだ...。完全に忘れている。
CSSで書けるということは出力できるはず。mixinにする。

px計算どうするかなとおもったけど、普通に0pxを加算した変数を定義するとなんとかなりそう。
初期値は全部数値だけ入れておいて、mixin内の変数定義でpxを追加する。

mixin.scss

function.scss
@function decimal($number) {
  $value: $number;
  @return round($number * 10000) / 10000;
}
mixin.scss
@function decimal($number) {
  $value: $number;
  @return round($number * 10000) / 10000;
}
@mixin font-size($spFont, $spBase: 320, $pcFont: 16, $pcBase: 1400) {
  $value: $spFont;

  $spPx: $spFont + 0px;
  $spBasePx: $spBase + 0px;
  $fontSub: $pcFont - $spFont;
  $y: ($pcBase - $spBase) / $fontSub;
  $minWidth: $pcBase + 1px;
  @if ( $fontSub != 0 ) {
    font-size: calc(((100vw - #{$spBasePx}) / #{decimal($y)}) + #{$spPx} );
    @media screen and (min-width: #{$minWidth}) {
      font-size: #{$pcFont}px;
    }
  } @else {
    font-size: #{$value}px;
  }
}

PCのベースサイズを超えたらpx固定にするメディアクエリをつけておく。これつけておくと楽。PCベースサイズがmax-widthのときはこれでよかろ。場合によっちゃremでも。
小数点以下の処理はfunctionに丸投げ。
calc内の #{$var} はインターポレーションというらしい。関数も入れ込めるので重宝しそう。

SCSSの変数と、CSS3のcalc()を併用するには
インターポレーション, ShanaBrian

style.scss

style.scss
html{
  // ルートを62.5%にしておくとremが使いやすいような気がする
  font-size: 62.5%;
}
body {
  // width320pxのとき14px, width1400pxのとき16pxを基準とする
  // width375pxのとき14px, width1000pxのとき18pxならfont-size(14,375,18,1000)と指定する
  @include font-size(14);
  }
}

responsive()はブレークポイント用のやつ。念のため。なくてもいい。

PC時の最大幅以降 / 修正作業

SP幅はこれで問題なさそうなので、PCの基準値以降は別途設定する。
コンテンツの最大幅に合わせて62.5%で丸め込んでしまうことにする。
修正時はmixin名で検索すれば、大体なんとかなるかもしれない。

参考サイト

計算式関係

SCSS関係

CSS関係

計算機

0
2
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
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?