Shopify Horizon v4.1.4 アップデート解説

Shopify Horizon v4.1.4 アップデート解説

Shopify公式テーマ「Horizon」が v4.1.1 から v4.1.4 に進みました。本記事では、コードの差分を読み解きながら、v4.1.1 から v4.1.4 への変更内容と、ストア運営者が押さえておくべきポイントをまとめます。

前回の「v4.1.1 アップデート解説」ではカラーシステムの全面刷新を取り上げましたが、今回はその続きです。v4.1.1 から最新の v4.1.4 までの3リリース分(v4.1.2 は公式リリースノートが存在せず、実質 v4.1.1 → v4.1.3 → v4.1.4 の流れ)で何が変わったのかを整理します。

変更サマリー ― 「168ファイル変更」の中身

差分は 168ファイル変更(新規32・変更136)、+9,083行 / −4,237行。前回のカラーシステム刷新(322ファイル)よりは小規模ですが、これも中身を見ると「複数のファイルで使うCSSを共通化した」という1つの設計変更が全体に波及した結果でした。

その証拠に、新規追加された32ファイルのうち20個が「〇〇-styles.liquid」という名前のスニペットです。ボタン・チェックボックス・スウォッチ・数量セレクター・ダイアログ・カート文字組など、これまで特定のファイルの中に埋め込まれていたCSSが、独立したファイルに切り出されました。

ストア運営者が気にすべき変更は、大きく次の通りです。

変更 影響範囲 対応の要否
① 複数ファイルで使うCSSの共通化 ページ読み込み時のCSS量・表示の安定性 不要(自動で適用。カスタムCSSで直接セレクタ指定がある場合のみ要確認)
② メガメニューのキーボード/スクリーンリーダー対応強化 ヘッダーのドロップダウンメニュー操作性 不要(自動で適用)
③ Quick Add/バリアント選択の競合状態修正 連打・高速操作時のカート追加の正確性 不要(自動で適用)
④ ヘッダー高さ計測の最適化 初期表示のレイアウトずれ(CLS)抑制 不要(自動で適用)
⑤ 多言語対応の拡大(アラビア語・ヘブライ語・ウルドゥー語) 右から左に書く言語(RTL)でのストア展開 該当ストアのみ確認

①だけが構造的な変更で、残りは着実なバグ修正・アクセシビリティ改善の積み重ねです。順に解説します。

変更点① ― 複数ファイルで使うCSSを共通化した(今回最大の変更)

前提:Shopify Liquidの {% stylesheet %} タグ

Shopify Liquidの {% stylesheet %} タグは、section・block・snippetファイルごとにCSSを定義でき、そのページで実際に使われているファイルの分だけを1つのstyles.cssにまとめて配信する仕組みです(「サブセッティング」と呼ばれる最適化)。同じファイルが1ページ内で何度描画されても、そのCSSは重複せず1回だけ含まれます。

ここで大事なのは、「配信されるかどうか」の判定単位がファイルだということです。あるCSSルールをどのファイルに書くかが、そのまま「そのCSSが配信されるかどうか」を決めます。

見つかった本当の問題

今回、旧バージョン(v4.1.1)のソースを1つずつ直接確認しました。分かったのは、「{% style %}から{% stylesheet %}に変わった」という単純なタグの置き換えではなく、複数の異なるファイルが同じCSSを必要としているのに、そのCSSが特定の1つのファイルにしか書かれていなかったという問題でした。

この状態には、次の2つの不都合があります。

  • そのCSSを、常に読み込まれる共通ファイル(assets/base.css)に書いてしまうと、それを必要としないページにも配信され続ける
  • そのCSSを、利用する側の1つのファイルだけに書いてしまうと、他の利用先は「そのファイルが同じページで一緒に描画されること」を前提にすることになり、実際にはそのファイルが描画されないページではCSSが反映されない

今回のHorizonの変更は、この2つの不都合を解消するために、複数のファイルから参照されているCSSを、それぞれの利用先から独立した共通のファイルに切り出し、必要な側がそれぞれ明示的に読み込むようにした、という内容でした。旧ソースを実際に確認して分類した結果は次の通りです。

ケース1:全ページ共通ファイルに書かれていたCSSを、必要なページだけに絞った

チェックボックス・タグ状のUI(ピル)・商品カードのズーム表示など、一部の部品のCSSはassets/base.cssという、ページの内容に関わらず常に読み込まれる1枚のCSSファイルの中に書かれていました。その部品を1つも使わないページでも、CSSは問答無用で配信されていたことになります。

ケース2:1つのファイルにしかなかったCSSに、他のファイルが暗黙的に頼っていた

例えば「カートの文字組(フォントの太さ・書体)」のCSSは、v4.1.1ではcart-products.liquidというファイルの中にしか書かれていませんでした。ところが、同じクラス名はcart-summary.liquidという別のファイルでも使われています。つまりcart-summary.liquidは、「cart-products.liquidが同じページで一緒に読み込まれること」に、コード上は何も保証がないまま頼っていたわけです。実際に新設されたcart-typography-styles.liquidのドキュメントには「cart-productsとcart-summaryの両方で使う共有スタイル」と明記されており、これがまさに解消すべき問題でした。

ケース3:後からJavaScriptで追加される内容に、CSSが追いつかない

商品カードや動画、決済分割表示(Shop Pay installments)のように、ページが最初に表示された後でJavaScriptによって画面に追加される部品もあります。この場合、最初の読み込み時点ではその部品のファイルが使われていないため、サブセッティングの仕組み上CSSが配信されず、後から追加された瞬間に一瞬スタイル無しの状態(チラつき)が発生します。新設されたproduct-card-styles.liquidのドキュメントには「フィルターで0件になったグリッドでも、事前にこのCSSを読み込んでおける」と明記されており、まさにこの対策です。

検証:新設された20ファイルの内訳

新設された20個の*-styles.liquidのdoc注釈を1つずつ確認したところ、19個までが「Shared(共有)... used by(利用元)〇〇と△△」という文言を含んでいました。「base.cssにあったかどうか」よりも、「複数のファイルから参照されていること」自体が共通の実態だったということです。

唯一の例外はcard-hover-effect-styles.liquidです。他の19個とは逆に、個別スニペットに切り出すのではなく、常に読み込まれるlayoutファイル側から描画する方式が採られています。ドキュメントには「スニペット単位でしか収集されない仕組みだと、検索結果カードのようなグローバルな面でホバー効果が抜け落ちるため」と明記されており、これも「複数のファイルから参照されるCSSを、特定の1つのファイルだけに結びつけない」という同じ考え方の適用です。

実際に重複していたCSSの例

「複数のファイルが同じCSSを必要としているのに1つのファイルにしかなかった」ケースの中には、実際に同じ内容がコピー&ペーストで2ファイルに重複して書かれていたものもありました。.text-block--align-center.text-block--align-rightという2つのCSSルールは、v4.1.1ではblocks/_announcement.liquidsnippets/text.liquidの両方に、一字一句同じ内容で存在していました。この2つのファイルが同じページで一緒に表示される場合(例:お知らせバーとリッチテキストが両方あるページ)、このCSSは2重に配信されていたことになります。v4.1.4ではこの内容がtext-block-styles.liquidに一本化され、両ファイルはそこを{% render %}する形に変わりました。

カスタマイズへの影響

  • ストア側でカスタムCSSを書いていて、base.css由来のクラス名や、特定のコンポーネントファイルに直接書かれていたクラス名を上書きしている場合、そのルールが別スニペットに移動していることがあります。上書きが効かなくなった場合は移動先を確認してください。
  • 通常のテーマカスタマイザー操作のみのストアでは、表示の破綻は起きません。

変更点② ― メガメニューのキーボード/スクリーンリーダー対応強化

assets/header-menu.js に、キーボード操作専用のハンドラーが追加されました。

  • Escapeキーでサブメニューを閉じ、フォーカスを元の開閉ボタンに戻す
  • デスクトップのサブメニューに専用の開閉ボタン(disclosure control)を新設し、aria-expanded状態を明確化
  • オーバーフローメニュー(「もっと見る」に格納された項目)を閉じた際、フォーカスが非表示要素に残ってしまう問題を修正し、常に見えている「もっと見る」ボタンへ戻すように変更

コード内のコメントには「オーバーフローパネルを閉じると、フォーカスされていた要素が非表示になるため、常に見えている More トリガーにフォーカスを戻す」という設計意図が明記されており、キーボード・スクリーンリーダー利用者が操作の起点を見失わないための修正であることが分かります。

変更点③ ― Quick Addのバリアント選択に関する2つの堅牢化

リリースノートには「在庫切れの商品を選択した場合に、クイック追加ボタンが『選択』ではなく無効の『追加』と表示される問題を修正し、在庫切れボタンにカートアイコンが表示されるようにした」とあります。実装を確認すると、これはassets/quick-add.jsに新設された#isSelectedVariantUnavailable()が直接対応する修正でした。

コード内コメントには「単一オプションの商品カードでも、売り切れのスウォッチを選び直すと購入不可なバリアントに行き着くことがある。その場合は『追加』ではなく『選択』のままにして、購入者をバリアントピッカーへ導く(押しても反応しない無効な『追加』ボタンに行き着かせない)」と明記されており、ボタンの表示を「追加」か「選択」かに振り分ける処理に、購入不可判定の分岐が追加されたことが分かります。

これとは別に、新設されたassets/variant-resolution.jsは、カートに追加する直前の「どのバリアントIDを送信するか」を決定する処理を、単体テスト可能な形に切り出したモジュールです。コード内のドキュメントコメントに、次のような優先順位が明記されています。

  1. そのカート追加リクエスト自身が待っていたサーバー側の再取得結果(resolvedVariantId
  2. バリアントピッカーの選択状態(intendedVariantId)― 常に最新なので信頼できる
  3. hidden inputの値(hiddenInputValue)― サーバー側の再取得完了後のみ信頼できる
  4. 上記すべてが得られない、または在庫切れで購入不可な場合は null を返し、カート追加自体を中止する

これは「バリアントピッカーをすばやく連続操作した際に、意図しない(古い・在庫切れの)バリアントがカートに追加されてしまう」不具合を防ぐための、上記とは別の堅牢化です。

変更点④ ― ヘッダー高さ計測の最適化(レイアウトずれ対策)

新設された snippets/measure-header-heights.liquid は、--header-height--header-group-height というCSS変数を「実測」するJavaScript処理を、その値を実際に必要とするセクション/ブロックからだけ呼び出す仕組みです。

コード内コメントに「measurement forces layout at parse time(計測処理はその場でレイアウト計算を強制する)ので、消費側の最も狭い条件でガードして呼び出すこと」と明記されており、全ページで無条件にヘッダー高さを計測していた処理を、実際に必要なページ・条件だけに絞ることで、初期表示時の不要なレイアウト計算を削減しています。リリースノートの「Reduced layout work during initial page render by measuring header height only on pages that need it」に対応する変更です。

変更点⑤ ― 多言語対応の拡大(アラビア語・ヘブライ語・ウルドゥー語)

locales/ar.jsonlocales/he.jsonlocales/ur.json(およびそれぞれの.schema.json)が新規追加されました。いずれも右から左に書く言語(RTL)です。該当言語でストアを多言語展開している場合のみ関係します。

その他の変更

変更 概要
ヘッダーロゴの切替ロジック変更 blocks/_header-logo.liquid。ロゴの「通常時/ヘッダー透過時(インバース)」の切り替えを、use_inverse_logo条件分岐によるクラス出し分けに変更
フィルターの色オーバーライド修正 blocks/filters.liquid。カスタム色設定が、従来は「横並び(horizontal)」レイアウトの時しか適用されなかったのを、縦並び(vertical)でも同様に適用されるよう修正
Spacerブロックのモバイル崩れ修正 blocks/spacer.liquid。カラム内でモバイル用の固定px幅スペーサーが flex: 0 の指定により潰れてしまう問題を、flex: 0 0 auto に変更して解消
グリッド密度コントロールの表示条件見直し snippets/grid-density-controls.liquid。列数切り替えボタンの表示・非表示をブレークポイントごとに個別指定できるよう調整
カートの文字組の一本化 snippets/cart-summary.liquid が新設の cart-typography-styles を読み込むよう変更。「変更点①」で触れた、複数ファイルが必要とするCSSが1つのファイルにしかなかったケースの1つ
カート概要(summary)のスクロール追従修正 blocks/_cart-summary.liquid。「画面端まで表示」設定を有効にした際のレイアウトで、.cart-summary--extend .cart-summary__innerに指定されていたheight: 100%を削除。この高さ指定がposition: stickyの動作を妨げており、スクロールしてもカート概要が画面内に留まらない原因になっていた
CSSバンドルサイズの継続的な削減 assets/base.cssから未使用のアニメーション・トランジション定義や重複したCSS変数を削除(v4.1.3・v4.1.4双方のリリースノートに記載)

まとめ

v4.1.1 → v4.1.4 は アップデート推奨 です。前回のようなカスタマイザーの見た目に直結する変更ではなく、表示速度・レイアウト安定性・アクセシビリティ・操作の堅牢性を積み重ねる内容が中心でした。

  • 複数ファイルで使うCSSの共通化は、ユーザーからは見えない部分での改善ですが、複数の部品が同じCSSに依存している箇所ほど、以前は不具合が出やすく、今回の変更で安定した構造になったと言えます。
  • メガメニューのキーボード対応・Quick Addの競合状態修正は、いずれも「限られた操作条件でだけ発生する」不具合への地道な対応で、日々の運用で気づきにくい改善です。
  • カスタムCSSで細かくスタイルを上書きしているストアは、更新後に商品カード・フィルター・カート周りの表示を一度確認することをお勧めします。

ファイル構成がバージョンごとに変わりうるテーマだからこそ、「どこを触ったか」を常に把握できるGit管理(upstream/horizon ブランチでのオリジナル追跡)が、こうした地道なアップデートでも効いてきます。

Back to blog