レスポンシブサイトでするっと可変する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が好きだ。この時はまだ穴にはまったことに気が付いていない。)
// 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);
};
<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 decimal($number) {
$value: $number;
@return round($number * 10000) / 10000;
}
@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
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名で検索すれば、大体なんとかなるかもしれない。
参考サイト
計算式関係
- CSSだけでレスポンシブ対応 font-sizeを画面に合わせて自動で変える, WEB DESIGN TEXTBOOK
- あまり知られていないcalc()とvwを使ったお手軽レスポンシブ制御, Qiita
- 【CSS】結局レスポンシブでのフォントサイズはどう書くべき?, ペコプラ
SCSS関係
- SCSSの変数と、CSS3のcalc()を併用するには, Qiita
- インターポレーション, ShanaBrian
- 知っておくと便利!!SASSで用意されている8つの演算関数をまとめてみた, Webクリエイターのアトリエ