Flexboxでマルチカラムレイアウトを実現するには「justify-content: space-between;」で「左右均等配置」するのが一般的な方法です。
しかし、この方法だと最終行の要素が足りない場合に、要素が左寄せにならず、左右に分かれてしまいます。
以下の画像のようになります。
この問題の解決方法を書いていきます。
Flexboxでマルチカラムレイアウトが左右に分かれる問題の解決法
3カラムの場合(要素数が固定)
まずは「3カラム」を実現させるコードと解決策を載せていきます。
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>test</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<section id="card">
<div class="card__contents">
<article class="card__block">
<div><img src="images/card-img-01.jpg" alt=""></div>
<h3>タイトル1</h3>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing earticlet.
</div>
</article>
<article class="card__block">
<div><img src="images/card-img-02.jpg" alt=""></div>
<h3>タイトル2</h3>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing earticlet.
</div>
</article>
<article class="card__block">
<div><img src="images/card-img-03.jpg" alt=""></div>
<h3>タイトル3</h3>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing earticlet.
</div>
</article>
<article class="card__block">
<div><img src="images/card-img-04.jpg" alt=""></div>
<h3>タイトル4</h3>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing earticlet.
</div>
</article>
<article class="card__block">
<div><img src="images/card-img-05.jpg" alt=""></div>
<h3>タイトル5</h3>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing earticlet.
</div>
</article>
</div>
</section>
<script src="https://code.jquery.com/jquery-3.4.0.min.js" integrity="sha256-BJeo0qm959uMBGb65z40ejJYGSgR7REI4+CW1fNKwOg=" crossorigin="anonymous"></script>
<script src="js/my.js"></script>
</body>
</html>
style.css
.card__contents{
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
}
.card__contents{
width: 1146px;
padding: 0 30px;
margin: 30px auto;
}
.card__contents::after{
content: '';
width: calc(100% / 3 - 20px);
display: block;
}
.card__block{
padding: 10px;
margin: 0 0 30px;
background-color: #dfdfdf;
border-radius: 4px;
}
.card__block{
width: calc(100% / 3 - 20px);
}
h3{
margin: 20px 0;
font-weight: bold;
}
解決策は、style.cssの12行目~16行目です。
マルチカラムレイアウトを囲む親要素に、「::after」疑似要素を付けて、
最終行の末尾に空の要素を追加しています。
末尾に見えない要素が1個入るので、
左寄せになったように見せる事ができます。
この方法は、あらかじめ要素の個数が決まっている場合に限ります。
初めから要素数が5個しかないと分かっている場合のみ、空の要素を入れて数を6個に合わせているのです。
それでは、要素の個数が不確定の場合はどうでしょうか?
例えば、
ブログの記事一覧などをマルチカラムレイアウトで表示する場合、記事の個数は不確定です。
ブログをカテゴリー別に検索した場合、何個の記事がヒットするかは不確定ですよね?
次は要素の個数が不確定の場合の解決策を書きます。
3カラムの場合(要素数が不確定)
jQueryを使って要素数を取得する事で対策します。
先程のHTMLを使い回して「CSS」を少し変えていきます。
my.js
$(function(){
for(var n=0; n<=3; n++){
if(($('.card__block').length) === ((n * 3) + 2)){
$('.card__contents').append('<article class="card__block"></article>');
}
}
});
style.css
.card__contents{
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
}
.card__contents{
width: 1146px;
padding: 0 30px;
margin: 30px auto;
}
.card__block{
padding: 10px;
margin: 0 0 30px;
background-color: #dfdfdf;
border-radius: 4px;
}
.card__block{
width: calc(100% / 3 - 20px);
}
.card__block:empty{
background-color: #fff;
}
h3{
margin: 20px 0;
font-weight: bold;
}
先程はCSSで空の要素を追加しましたが、
今回は、「my.js」というjqueryファイルを使って動的に空の要素を追加します。
「my.js」の3行目で、「$(.card__block).length」を使って要素数を取得、
要素数が2個か、5個か、8個の場合のみ、空の要素1つ追加しています。
これにより、要素が2個しかない場合でも左寄せに対応します。
対応する行数を増やしたい場合は、
「my.js」の2行目の「forループ」の回数を増やす事で対応してください。
style.cssでは、「::after」疑似要素で空の要素を増やす処理を削除(jQueryで代替)。
21行目~23行目で「:empty」疑似要素を使って、jQueryによって追加した空要素のデザインを調整しています。
今回はbackground-colorを#fffに戻しています。
4カラムの場合(要素数が固定)
まず初めに、4カラムで最終行の要素が不足している場合、
どういう現象が起きるのかを見てみます。
【要素が2個足りない場合】
最終行が左右に別れます。
【要素が1個足りない場合】
最終行が3カラムの均等な間隔に別れます。
解決法は、要素数が確定している場合
CSSの疑似要素で埋めていく方法が有効です。
それでは、「4カラム」を実現させるコードと解決策を載せていきます。
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>test</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<section id="card">
<div class="card__contents">
<article class="card__block">
<div><img src="images/card-img-01.jpg" alt=""></div>
<h3>タイトル1</h3>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing earticlet.
</div>
</article>
<article class="card__block">
<div><img src="images/card-img-02.jpg" alt=""></div>
<h3>タイトル2</h3>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing earticlet.
</div>
</article>
<article class="card__block">
<div><img src="images/card-img-03.jpg" alt=""></div>
<h3>タイトル3</h3>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing earticlet.
</div>
</article>
<article class="card__block">
<div><img src="images/card-img-04.jpg" alt=""></div>
<h3>タイトル4</h3>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing earticlet.
</div>
</article>
<article class="card__block">
<div><img src="images/card-img-05.jpg" alt=""></div>
<h3>タイトル5</h3>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing earticlet.
</div>
</article>
<article class="card__block">
<div><img src="images/card-img-06.jpg" alt=""></div>
<h3>タイトル6</h3>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing earticlet.
</div>
</article>
<article class="card__block">
<div><img src="images/card-img-07.jpg" alt=""></div>
<h3>タイトル7</h3>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing earticlet.
</div>
</article>
<article class="card__block">
<div><img src="images/card-img-08.jpg" alt=""></div>
<h3>タイトル8</h3>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing earticlet.
</div>
</article>
<article class="card__block">
<div><img src="images/card-img-09.jpg" alt=""></div>
<h3>タイトル9</h3>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing earticlet.
</div>
</article>
<article class="card__block">
<div><img src="images/card-img-10.jpg" alt=""></div>
<h3>タイトル10</h3>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing earticlet.
</div>
</article>
</div>
</section>
<script src="https://code.jquery.com/jquery-3.4.0.min.js" integrity="sha256-BJeo0qm959uMBGb65z40ejJYGSgR7REI4+CW1fNKwOg=" crossorigin="anonymous"></script>
<script src="js/my.js"></script>
</body>
</html>
sytle.css
.card__contents{
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
}
.card__contents{
width: 1146px;
padding: 0 30px;
margin: 30px auto;
}
.card__contents::after{
content: '';
width: calc(100% / 4 - 22px);
display: block;
}
.card__contents::before{
content: '';
width: calc(100% / 4 - 22px);
display: block;
order: 1;
}
.card__block{
padding: 10px;
margin: 0 0 30px;
background-color: #dfdfdf;
border-radius: 4px;
}
.card__block{
width: calc(100% / 4 - 22px);
}
h3{
margin: 20px 0;
font-weight: bold;
}
解決策は、style.cssの12行目~22行目です。
マルチカラムレイアウトを囲む親要素に、「::after」疑似要素と「::before」疑似要素を付けて、最終行の末尾に2個の空の要素を追加しています。
最終行が1要素だけ不足している場合は、
「::after」疑似要素のみで対応できます。
対策後は以下のように
左寄せの様に見せる事ができます。
4カラムの場合(要素数が不確定)
ブログのカテゴリ一覧などの様に、
マルチカラムレイアウトに表示する要素数が不確定の場合は、jQueryで対応します。
jQueryの追加と、「CSS」の内容を少し変えていきます。
my.js
$(function(){
var lastBlock = $('.card__block').length;
for(var n=0; n<=3; n++){
if((lastBlock) === ((n * 4) + 2)){
$('.card__contents').append('<article class="card__block"></article>')
.append('<article class="card__block"></article>');
} else if((lastBlock) === ((n * 4) + 3)){
$('.card__contents').append('<article class="card__block"></article>');
}
}
});
style.css
.card__contents{
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
}
.card__contents{
width: 1146px;
padding: 0 30px;
margin: 30px auto;
}
.card__block{
padding: 10px;
margin: 0 0 30px;
background-color: #dfdfdf;
border-radius: 4px;
}
.card__block{
width: calc(100% / 4 - 22px);
}
.card__block:empty{
background-color: #fff;
}
h3{
margin: 20px 0;
font-weight: bold;
}
my.jsの4行目~6行目は、不足した2要素を追加する処理、
7行目~8行目は、不足した1要素を追加する処理を行っています。
style.cssの「::after」「::before」はjQueryで代替したので削除。
21行目~23行目で、「:empty」疑似要素を使ってjQueryで追加した要素のデザインを調整しています。
5カラム以上のマルチカラムレイアウトは、jQueryのみで対応していきます。
「ここまでしてFlexboxを使う意味があるのか?」と思ってしまいますが、実はもっと簡単な方法はあります。
要素間の余白が「px」固定の場合は、以下の方法を使った方がjQuery不要でラクです。
今回紹介した方法は、要素間の余白を「%」指定にした場合でも使えるので、
必要に応じて参考にして頂ければと思います。
スポンサーリンク |
|
|
|