2026年5月24日
2026年5月24日
WordPressの記事一覧をCSS Gridで1・2・3カラムに切り替える方法
WordPress の記事一覧を、読者がボタンで 1・2・3 カラムに切り替えられるようにするには、一覧を包む要素に CSS Grid を指定し、カラム数を data-columns 属性で切り替えます。JavaScript はその属性を書き換えるだけにして、見た目はすべて CSS で決めると、壊れにくく直しやすい作りになります。
この記事のコードは、2026年11月時点の WordPress 6.9 で使える関数と、主要ブラウザーで動く CSS・JavaScript だけで書いています。クラシックテーマ(PHP のテンプレートファイルで作るテーマ)の子テーマに追加する前提です。
先に確認: カラム数を固定するだけならエディターで設定できる
読者に切り替えさせる必要がなく、「一覧を 3 カラムで表示したい」だけなら、コードは要りません。ブロックテーマでは、サイトエディターで一覧のテンプレートを開き、「クエリーループ」の中の「投稿テンプレート」ブロックを選んで、ツールバーの「グリッド表示」を選ぶと、カラム数を指定できます。
この記事は、読者が表示を選べるようにしたい場合の作り方です。
全体の構成
| ファイル | 役割 |
|---|---|
functions.php |
CSS と JavaScript を一覧ページでだけ読み込む |
index.php(または archive.php) |
切り替えボタンと、data-columns 属性を付けた一覧を出力する |
css/layout-switch.css |
data-columns の値ごとにカラム数を決める |
js/layout-switch.js |
ボタンが押されたら data-columns を書き換え、選択を保存する |
手順1: CSS でカラム数を決める
子テーマのフォルダーに css/layout-switch.css を作ります。
.post-grid {
display: grid;
gap: 1.5rem;
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.post-grid[data-columns="1"] {
grid-template-columns: minmax(0, 1fr);
}
.post-grid[data-columns="2"] {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.post-grid[data-columns="3"] {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.post-grid img {
width: 100%;
height: auto;
}
.layout-switch {
display: flex;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.layout-switch button[aria-pressed="true"] {
font-weight: bold;
text-decoration: underline;
}
/* スマートフォンでは常に 1 カラムにし、切り替えボタンも隠す */
@media (max-width: 781px) {
.post-grid[data-columns] {
grid-template-columns: minmax(0, 1fr);
}
.layout-switch {
display: none;
}
}
ポイントは次の 2 つです。
1frではなくminmax(0, 1fr)にしているのは、長い URL や大きな画像があってもカラムの幅が均等に保たれるようにするためです。1frだけだと、中身の最小幅より狭くならず、列の幅がずれることがあります。- カラム数は、一覧の要素そのものに付けた
data-columns属性で切り替えます。親要素にクラスを付けて子孫セレクターで指定する方法もありますが、JavaScript でクラスを付ける要素と CSS のセレクターがずれると効かなくなるので、同じ要素の属性にそろえておくと間違えにくくなります。
手順2: 切り替えのスクリプトを書く
子テーマのフォルダーに js/layout-switch.js を作ります。
( function () {
var grid = document.querySelector( '.post-grid' );
var buttons = document.querySelectorAll( '.layout-switch [data-columns]' );
if ( ! grid || ! buttons.length ) {
return;
}
var STORAGE_KEY = 'mytheme-columns';
function apply( columns ) {
grid.setAttribute( 'data-columns', columns );
buttons.forEach( function ( button ) {
var pressed = button.getAttribute( 'data-columns' ) === columns;
button.setAttribute( 'aria-pressed', pressed ? 'true' : 'false' );
} );
}
// 前回選んだカラム数があれば使う(保存できない環境では無視する)
var saved = null;
try {
saved = window.localStorage.getItem( STORAGE_KEY );
} catch ( e ) {}
if ( saved === '1' || saved === '2' || saved === '3' ) {
apply( saved );
}
buttons.forEach( function ( button ) {
button.addEventListener( 'click', function () {
var columns = button.getAttribute( 'data-columns' );
apply( columns );
try {
window.localStorage.setItem( STORAGE_KEY, columns );
} catch ( e ) {}
} );
} );
} )();
- 選んだカラム数はブラウザーの
localStorageに保存し、次にページを開いたときも同じ表示にします。プライベートブラウズなどで保存できない場合も、エラーで止まらないようtryで囲んでいます。 aria-pressedは、ボタンが押された状態かどうかをスクリーンリーダーに伝える属性です。CSS でも、押されているボタンの見た目を変えるのに使っています。
手順3: functions.php で読み込む
CSS と JavaScript は、<link> や <script> をテンプレートに直接書かず、wp_enqueue_scripts フックで読み込みます。子テーマの functions.php に追記します。
<?php
// 子テーマの functions.php に追記する
add_action( 'wp_enqueue_scripts', 'mytheme_layout_switch_assets' );
function mytheme_layout_switch_assets() {
// 投稿一覧(ブログのトップ・アーカイブ・検索結果)だけで読み込む
if ( ! is_home() && ! is_archive() && ! is_search() ) {
return;
}
$dir = get_stylesheet_directory_uri(); // 親テーマに置く場合は get_template_directory_uri()
wp_enqueue_style( 'mytheme-layout-switch', $dir . '/css/layout-switch.css', array(), '1.0.0' );
wp_enqueue_script(
'mytheme-layout-switch',
$dir . '/js/layout-switch.js',
array(),
'1.0.0',
array(
'in_footer' => true,
'strategy' => 'defer',
)
);
}
wp_enqueue_script() の 5 番目の引数に配列を渡す書き方(strategy で defer を指定)は WordPress 6.3 から使えます。defer を付けたスクリプトは HTML を読み終えてから実行されるので、スクリプトの中で一覧の要素を探しても見つからない、ということが起きません。
子テーマの functions.php は、既存の内容の後ろに追記します。ファイルの先頭にはすでに <?php があるので、2 つ目は書きません。読み込みの仕組みはWordPressのwp_enqueue_scriptsでJS・CSSを読み込む方法で詳しく説明しています。
手順4: テンプレートに一覧とボタンを書く
記事一覧を出しているテンプレート(多くのテーマでは index.php、カテゴリーなどの一覧は archive.php)を、親テーマから子テーマへコピーして編集します。一覧部分を次のように書きます。
<?php get_header(); ?>
<main id="main" class="site-main">
<div class="layout-switch" role="group" aria-label="一覧の表示カラム数">
<button type="button" data-columns="1" aria-pressed="false">1カラム</button>
<button type="button" data-columns="2" aria-pressed="false">2カラム</button>
<button type="button" data-columns="3" aria-pressed="true">3カラム</button>
</div>
<?php if ( have_posts() ) : ?>
<div class="post-grid" data-columns="3">
<?php while ( have_posts() ) : the_post(); ?>
<article id="post-<?php the_ID(); ?>" <?php post_class( 'post-grid__item' ); ?>>
<a href="<?php the_permalink(); ?>">
<?php if ( has_post_thumbnail() ) : ?>
<?php the_post_thumbnail( 'medium_large' ); ?>
<?php endif; ?>
<h2 class="post-grid__title"><?php the_title(); ?></h2>
</a>
<?php the_excerpt(); ?>
</article>
<?php endwhile; ?>
</div>
<?php the_posts_pagination(); ?>
<?php else : ?>
<p>投稿が見つかりませんでした。</p>
<?php endif; ?>
</main>
<?php get_footer(); ?>
- 最初に表示するカラム数は、一覧の
data-columns="3"と、3カラムのボタンのaria-pressed="true"で決めています。既定を 2 カラムにしたい場合は両方を合わせて変えます。 mainのidやクラス名は、使っているテーマの元のテンプレートに合わせてください。サイドバーや本文の幅はテーマの CSS が決めているので、元のテンプレートの外側の構造は残し、一覧の部分だけを置き換えるのが安全です。- ボタンを
<button type="button">にしているので、キーボードの Tab キーで移動して Enter キーやスペースキーでも切り替えられます。
手順5: 表示を確かめる
- 一覧ページを開き、ボタンを押してカラム数が変わることを確かめる。
- ページを再読み込みして、選んだカラム数のままになっていることを確かめる。
- ブラウザーの幅を 781px 以下に狭め(開発者ツールのデバイス表示でも可)、1 カラムになり、ボタンが消えることを確かめる。
切り替わらないときは、開発者ツールで次を確認します。
- 「Network」(ネットワーク)で
layout-switch.cssとlayout-switch.jsが 200 で読み込まれているか。404 なら、ファイルの置き場所とget_stylesheet_directory_uri()(子テーマ)・get_template_directory_uri()(親テーマ)の使い分けを見直します。 - 「Elements」(要素)で、ボタンを押したときに
.post-gridのdata-columnsが変わっているか。変わっていれば CSS 側、変わっていなければ JavaScript 側の問題です。 - キャッシュ系のプラグインや CDN を使っている場合は、キャッシュを消してから確認します。CSS や JavaScript を直したときは、
wp_enqueue_style()・wp_enqueue_script()のバージョン(1.0.0)を上げると、ブラウザーに古いファイルが残りにくくなります。
関連記事
参考: wp_enqueue_script()(WordPress Developer Resources)、grid-template-columns(MDN)、aria-pressed(MDN)