Quantcast
Channel: CSSタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8572

styled-components を使った Bootstrap 流レスポンシブ Web デザイン

$
0
0

はじめに

CSS フレームワークで有名な Bootstrapにはレスポンシブ Web デザインを構築するための便利な Sass mixins(e.g. media-breakpoint-up, media-breakpoint-down etc.)があります。今回、styled-componentsを利用するにあたり Bootstrap と同等のメディアクエリを作成する関数を紹介します。また、関数の利便性を考慮して TypeScriptを採用しています。

TL;DR

styled-components でレスポンシブ Web デザインを構築する場合、下記コードのように記述できるようになります。

pages/index.tsx
importstyledfrom'styled-components'import{breakpointUp,breakpointDown}from'../utils/breakpoints'...constContainer=styled.div`
  padding: 40px;

  ${breakpointDown('md')} { // プレースホルダーは @media (min-width: 768px) に置換されます。
    padding-right: 6.25%;
    padding-left: 6.25%;
  }
`constCard=styled.li`
  position: relative;
  display: flex;

  ...

  ${breakpointUp('md')} { // プレースホルダーは @media (max-width: 767.98px) に置換されます。
    &:hover {
      color: var(--base-link-color);
      box-shadow: 0 0 0 2px;
    }
  }
`

Bootstrap のブレークポイントの仕様

まずは Bootstrap の Sass mixins について解説します。なお、これから解説する仕様は現在(2020/06/03 現在)策定中の Bootstrap v5 の考案になります。策定中の GitHub issueにある下図と併せて読み進めていただけると理解しやすいかと思います。また、図内の黒丸(●)と白丸(○)は数学の座標で使われる記号で、黒丸は含む、白丸は含まないを意味します。

69884221-ac5bdb80-131a-11ea-933e-d5fd476fcd02.png

はじめに、理解しやすい media-breakpoint-upについて解説します。こちらは指定された引数(ブレークポイント)以上の画面幅に適用されるメディアクエリを作成します。上図の場合は、md(768px)を引数に指定しているので @media (min-width: 768px) { ... }が作成されます。逆に media-breakpoint-downは指定された引数(ブレークポイント)未満の画面幅に適用されるメディアクエリを作成します。ここで作成されるメディアクエリには ブレークポイントを含まれないことに注意してください。上図の場合は、sm(576px)を引数に指定されているので @media (max-width: 575.8px) { ... }が作成されます。ちなみに、0.01 px ではなく 0.02 px を減らしている理由は Safari の端数処理を考慮しているからです。詳しくはこちらを参照ください。

定数の宣言

まずは、各ブレークポイントを定数で管理します。型のメンバーに readonly修飾子を指定する、Numeric Literal Types(数値リテラル)として適用するために const アサーションを利用します。readonly修飾子を使えば、読み込み専用にできます。つまり、ある値に初期値を割り当てた後でその値を変更できないことを宣言できます。また、Numeric Literal Types により型推論から各ブレークポイントの値が把握しやすくなります。

constants/breakpoints.ts
exportconstbreakpoints={xs:0,sm:576,md:768,lg:992,xl:1200,}asconst

ブレークポイントの定数は ES Modules で import / export します。また、ブレークポイント名の型をのちに作成する関数で利用したいので Type alias(型エイリアス)typeofキーワードkeyofキーワードを用いて宣言します。typeofキーワードと keyofキーワードの併用で各ブレークポイント名の Union Types(ユニオン型)を生成できます。

utils/breakpoints.ts
import{breakpoints}from'../constants/breakpoints'typeBreakpoints=keyoftypeofbreakpoints// 'xs' | 'sm' | 'md' | 'lg' | 'xl'

ヘルパー関数の作成

本題の関数を作成する前にヘルパー関数を用意します。用意するヘルパー関数は breakpointNext, breakpointMin, breakpointMax の 3 つになります。では、順番に説明します。

breakpointNext

breakpointNext は指定された引数(ブレークポイント名)の次のブレークポイント名を返す関数です。たとえば 'md'を引数に指定する場合、戻り値が 'lg'になります。'xl'のような次のブレークポイントがない場合、戻り値は nullになります。

utils/breakpoints.ts
constbreakpointNext=(name:Breakpoints)=>{constbreakpointNames=Object.keys(breakpoints)asBreakpoints[]constnextIndex=breakpointNames.indexOf(name)+1if(nextIndex<breakpointNames.length){returnbreakpointNames[nextIndex]}else{returnnull}}

TypeScript の解説をします。breakpointNext の引数は各ブレークポイント名を指定することを期待しているので、さきほど作成した Breakpoints で型を制約します。後述する breakpointMin, breakpointMax も同様です。あと、Object.keys()メソッドで breakpointNames 変数を宣言している行に着目してください。ここでは 型アサーションを利用しています。

型アサーションには 2 つの構文があります。1 つは <>を使用した構文で、もう 1 つは asシグネチャを使用した構文になります。2 つの構文は同等ですが、前者は JSX の構文とぶつかる可能性があるので、後者の asシグネチャを使用することを推奨します。

Object.keys()メソッドで返す配列の型推論は string[]になります。こちらを型アサーションを利用してブレークポイント名が格納される配列の型に ダウンキャスト1します。

breakpointMin

breakpointMin はメディアクエリの min-width の値を返す関数です。たとえば引数に 'md'を指定した場合、戻り値は 768になります。引数に 'xs'が指定された場合、戻り値は nullになります。

utils/breakpoints.ts
constbreakpointMin=(name:Breakpoints)=>{constmin=breakpoints[name]returnmin!==0?min:null}

breakpointMax

breakpointMax はメディアクエリの max-width を返す関数です。たとえば引数に 'md'を指定した場合、戻り値は 575.8になります。引数に 'xs'が指定された場合、戻り値は nullになります。

utils/breakpoints.ts
constbreakpointMax=(name:Breakpoints)=>{constmax=breakpoints[name]returnmax&&max>0?max-0.02:null}

すべてのヘルパー関数を用意できましたので、本題の関数を作成しましょう。

本題

作成する関数は、breakpointUp, breakpointDown, breakpointBetween, breakpointOnly の 4 つになります。では、順番に説明します。

breakpointUp

breakpointUp は最小幅を定義するメディアクエリを返す関数です。Bootstrap のブレークポイントの仕様で先述した media-breakpoint-upと同等です。ヘルパー関数 breakpointMin が nullを返した場合、メディアクエリを生成せず、アンパサンド(&)を返します。& は styled-components で生成される一意のクラス名に置換されます。後述する他の関数でも同様の処理を行います。

utils/breakpoints.ts
exportconstbreakpointUp=(name:Breakpoints)=>{constmin=breakpointMin(name)if(min){return`@media (min-width: ${min}px)`}else{return'&'}}

breakpointDown

breakpointDown は最大幅を定義するメディアクエリを返す関数です。Bootstrap のブレークポイントの仕様で先述した media-breakpoint-downと同等です。

utils/breakpoints.ts
exportconstbreakpointDown=(name:Breakpoints)=>{constmax=breakpointMax(name)if(max){return`@media (max-width: ${max}px)`}else{return'&'}}

breakpointBetween

breakpointBetween は 2 つのブレークポイントで形成される画面幅に適用するメディアクエリを返す関数です。2 つの引数が lower < upper の大小関係になるようにブレークポイント名を指定します。たとえば lower 引数に 'sm'、upper 引数に 'lg'を指定した場合、戻り値は @media (min-width: 576px) and (max-width: 991.98px)になります。

utils/breakpoints.ts
exportconstbreakpointBetween=(lower:Breakpoints,upper:Breakpoints)=>{constmin=breakpointMin(lower)constmax=breakpointMax(upper)if(min!==null&&max!==null){return`@media (min-width: ${min}px) and (max-width: ${max}px)`}elseif(max===null){returnbreakpointUp(lower)}elseif(min===null){returnbreakpointDown(upper)}}

breakpointOnly

breakpointOnly は指定したブレークポイントのみに適用されるメディアクエリを返す関数です。たとえば 'md'を引数に指定した場合、戻り値は @media (min-width: 768px) and (max-width: 991.98px)になります。

utils/breakpoints.ts
exportconstbreakpointOnly=(name:Breakpoints)=>{constnext=breakpointNext(name)if(next===null)returnbreakpointUp(name)...constmin=breakpointMin(name)constmax=breakpointMax(next)if(min!==null&&max!==null){return`@media (min-width: ${min}px) and (max-width: ${max}px)`}elseif(max==null){returnbreakpointUp(name)}elseif(min==null){returnbreakpointDown(next)}}

TypeScript の解説をします。① の nullチェックにより、①以降の next 変数の型を絞り込んでいます。2これにより breakpointMax, breakpointDown の引数には nullがない型推論になり、コンパイルエラーになりません。

おわりに

いかがでしたでしょうか。今回紹介した内容は styled-components でスタイリングする方法を対象にしていますが、Bootstrap のブレークポイントの仕様は styled-components 以外のスタイリングでも活用できます。また、TypeScript を利用することで設定されているブレークポイント、開発者の意図を把握しやすくなります。本記事が読者の Bootstrap のブレークポイントの仕様、および、TypeScript の理解の一助になれば幸いです。


  1. 抽象的な型から詳細な型を付与することを「ダウンキャスト」といいます。 

  2. TypeScript はフローベースの型推論を行うため、プログラマがコードを読むときと同様の型の絞り込みを行ってくれます。 


Viewing all articles
Browse latest Browse all 8572

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>