関連記事カードのスマホ表示で「左側だけ変な余白が出る」という指摘をもらって調べたら、原因はまた同じパターンでした。
Cocoon本体のモバイル用CSSに、こちらのクラス指定が詳細度で負けていたんです。
正直に告白すると、この構造の罠に引っかかるのは今回で3回目です。
今回の症状: PCは無事、スマホだけ左に余白
関連記事カードのグリッド(.c-related-articles__grid、実装は<ul>要素です)にpadding: 0を指定していたのに、スマホ幅で見ると左側だけ26pxの余白が出続けていました。
PCでは問題なく表示されていたので、最初は見た目のチェックだけでは気づけませんでした。
「PCは平気、スマホだけ崩れる」というのが、後から思えば一番のヒントでした。
原因はCocoon本体の、要素+クラスの組み合わせ
調べてみると、Cocoon本体側が@media (max-width: 834px) { .article ul, .article ol { padding-left: 26px } }というルールで、記事本文ラッパー.article配下のul・olに直接padding-leftを当てていました。
このグリッドも.articleの中にあるulなので、そのまま対象にマッチしてしまいます。
詳細度で比べると、クラスの数はこちらの.c-related-articles__gridもCocoon側の.article ulも1つで同点ですが、その次に効く要素セレクタの数でCocoon側が1つ分勝ちます。
だから単一クラスの指定では勝てず、スマホ幅でだけ静かに上書きされていたわけです。
Stylesパネルでも追えるけど、量が多いと面倒だった
こういう競合は、ブラウザの開発者ツールのStylesパネルを見れば、打ち消し線付きでマッチした全ルールが表示されるので、本来はそれで特定できます。
ただ今回はスマホ幅のエミュレート中で、Cocoon本体側のルールも量が多く、目視で1つずつ追うのはさすがにきつい状況でした。
なので対象要素にマッチする全ルールを、メディアクエリの中身まで含めて一覧にするスクリプトを書いて、コンソールで実行しました。
const el = document.querySelector('.対象クラス');
if (!el) throw new Error('要素が見つかりません');
let out = [];
function walkRules(rules, path) {
for (const rule of rules) {
if (rule.type === CSSRule.MEDIA_RULE) { walkRules(rule.cssRules, path + ' @media(' + rule.conditionText + ')'); continue; }
if (!rule.selectorText) continue;
try {
if (el.matches(rule.selectorText)) {
out.push(`${path} :: ${rule.selectorText} => ${rule.style.cssText}`);
}
} catch(e) {}
}
}
for (const sheet of document.styleSheets) {
let rules; try { rules = sheet.cssRules; } catch(e) { continue; }
walkRules(rules, '');
}
out.join('\n');
全styleSheetを@mediaごと辿って、対象要素にマッチするルールを一覧にする内容です。
実行してみたら、案の定Cocoon本体の.article ulがリストに出てきて、犯人はすぐに特定できました。
2回経験してるのに、また時間がかかった
この「Cocoon本体のモバイル用メディアクエリに詳細度で負ける」という構造、実は今回が初めてではありません。
以前、目次デザインをカスタマイズしたときと、marginが効かなかったときにも、まったく同じ原因で引っかかっていました。
それでも、過去2回の教訓のおかげで「PCは平気・スマホだけ」という症状を見た瞬間に、疑うべき場所の見当はすぐつきました。
対処は!importantではなく、詳細度で上書き
直し方は!importantを使わず、親子のクラスを組み合わせて詳細度そのものを上げる方法を選びました。
負けていたのはpadding-leftだけだったので、上書きもそこだけに絞っています。
.c-related-articles {
&__grid {
padding: 0; // 通常はこれで足りる
}
// Cocoon本体の詳細度に負ける場合はこう上書きする
.c-related-articles &__grid {
padding-left: 0;
}
}
// コンパイル後は .c-related-articles .c-related-articles__grid になり、
// クラス2つ分の詳細度でCocoon側の.article ulに勝てる
!importantで押し切ることもできますが、後から別のコンポーネントが増えたときに、今度はそっちが!important同士でぶつかる事故が起きやすくなります。
詳細度で解決しておけば、そういう将来の事故を1つ減らせます。
💡 Tips: 犯人探しの前に「.article配下かどうか」を先に確認する
Cocoon本体のこの手のルールは、記事本文ラッパー.article配下の要素を狙い撃ちすることが多いです。
新しいコンポーネントを本文エリアの中に置く場合は、実装前に対象の要素がulやolなど、Cocoon側が既にスタイルを当てている要素と被っていないか確認しておくと、今回のような後追いの調査を減らせます。
まとめ
同じ構造の罠に3回も引っかかったのは、正直まだ学習不足だと思います。
それでも、疑うべき場所への見当がつくまでの時間は確実に短くなっています。
次踏んだときも、今回のスクリプトを使えばまた数分で犯人を特定できるはずです。
たぶん4回目もあります。
そのときもこの記事を自分で読み返すと思います。

