この記事の概要
メディアクエリをたくさん書いていると、どの幅のときにどのスタイルが当たるのか、段々分からなくなってきませんか?
私は分からなくなります。
というわけで、メディアクエリ無しでできる範囲のレスポンシブデザインを考えてみました。
コンテナクエリが普通に使えるようになればこの記事は不要になるかもしれません。
完成物
次のような設定で作成しました。
- サイドバーとメイン要素
- デスクトップでは2カラム、モバイルでは1カラム
- メイン要素内にはたくさんの子アイテム
- 幅に応じてカラム数が変わる
コードはこちらです。
index.html
<!-- head要素などは省略 -->
<body>
<div class="container">
<h1 class="title">Layout with no media queries</h1>
<div class="contents">
<aside class="aside">
<ul class="list">
<li>foo</li>
<li>bar</li>
<li>baz</li>
<li>qux</li>
<li>quux</li>
</ul>
</aside>
<main class="main">
<div class="main-item">item 1</div>
<div class="main-item">item 2</div>
<div class="main-item">item 3</div>
<div class="main-item">item 4</div>
<div class="main-item">item 5</div>
<div class="main-item">item 6</div>
<div class="main-item">item 7</div>
<div class="main-item">item 8</div>
<div class="main-item">item 9</div>
<div class="main-item">item 10</div>
<div class="main-item">item 11</div>
<div class="main-item">item 12</div>
</main>
</div>
</div>
</body>
style.css
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
height: 100%;
}
body {
background-color: #f3f3f3;
display: flex;
flex-direction: column;
min-height: 100%;
}
.container {
display: flex;
flex: 1 0 auto;
flex-direction: column;
padding: 16px;
}
.title {
text-align: center;
}
.contents {
display: flex;
flex-wrap: wrap;
gap: 16px;
margin-inline: auto;
padding-block: 16px;
width: min(100%, 1024px);
}
.aside {
align-self: flex-start;
background-color: #fff;
border-radius: 8px;
flex-grow: 1;
min-width: 224px;
padding: 16px;
}
.list {
padding-inline-start: 1rem;
}
.main {
background-color: #fff;
border-radius: 8px;
display: grid;
gap: 16px;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
flex-grow: 1;
min-width: 288px;
padding: 16px;
}
.main-item {
align-items: center;
background-color: #ddd;
border-radius: 4px;
display: flex;
height: 100px;
justify-content: center;
}
サイドバーとメイン要素のレイアウト
説明に必要な部分のコードだけを抜粋します。
index.html
<div class="contents">
<aside class="aside"></aside>
<main class="main"></main>
</div>
style.css
.contents {
display: flex;
flex-wrap: wrap;
}
.aside {
align-self: flex-start;
flex-grow: 1;
min-width: 224px;
}
.main {
flex-grow: 1;
min-width: 288px;
}
-
.contents
にdisplay: flex;
とflex-wrap: wrap;
を指定し、.aside
と.main
にそれぞれmin-width
を指定することで、基本は横並びにしつつ、min-width
が確保できないときに折り返される -
.aside
と.main
の両方にflex-grow: 1;
を指定することで、可能な限り横幅が広がる -
.aside
にalign-self: flex-start;
を指定することで、縦に伸びなくなる(指定しないと、.main
の高さに追従してしまう)-
.contents
にalign-items: flex-start;
でも同じ効果が得られる
-
メイン要素内のアイテムのレイアウト
説明に必要な部分のコードだけを抜粋します。
index.html
<main class="main">
<div class="main-item">item 1</div>
<div class="main-item">item 2</div>
<div class="main-item">item 3</div>
<div class="main-item">item 4</div>
<div class="main-item">item 5</div>
<div class="main-item">item 6</div>
<div class="main-item">item 7</div>
<div class="main-item">item 8</div>
<div class="main-item">item 9</div>
<div class="main-item">item 10</div>
<div class="main-item">item 11</div>
<div class="main-item">item 12</div>
</main>
style.css
.main {
display: grid;
gap: 16px;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
-
.main
にdisplay: grid;
を指定し、grid-template-columns
にrepeat
とauto-fit
を組み合わせて指定する -
auto-fit
を指定することで、.main-item
が幅200px以上になるように自動で計算して配置される -
gap
を指定することで、それぞれの子要素の間に常に一定の余白が空く-
nth-child
などでmarginを指定すると、幅によって「何番目の要素に余白をつけるか」を制御しないといけなくなりがち
-
最後まで読んでくださってありがとうございます!
Twitterでも情報を発信しているので、良かったらフォローお願いします!
Devトークでのお話してくださる方も募集中です!