おーじぇいブログ

ただひたすらに書きます。

クリックすると開閉するQ&Aリストが、クリックしても別の部分が開閉する問題の解決策

経緯

以前自分が所属しているサークルの、新入生歓迎用ランディングページを制作した際、Q&Aリストを実装しました。 参考にしたコードはこちらです。

copypet.jp

その際、クリックしても別のQ&A部分が開いてしまうという問題が発生しました。 結果からすれば単純にコピペしていた自分が悪かったのですが、このコードがどのように動作しているのかが気になったので、色々と構造を調べてみました。

以下に掲載しているコードはこぴぺっと(copypet.jp)様のサイトより引用です。

解決方法

問題文を括っているinputタグのidと、問題文そのものであるlabelタグのforを同一にすると、うまく動くようになります。 例えば上のサイトに載っているサンプルコードにQ&Aを追加したいときは、

<div class="cp_actab">
    <input id="cp_tabfour034" type="checkbox" name="tabs">
    <label for="cp_tabfour034">質問テキスト</label>
    <div class="cp_actab-content">
    <p>答えテキスト</p>
    </div>
</div>

このようにinputタグのid属性・labelタグのfor属性に同一のcp_tabfour034という文字列を指定することで、正常に動くようになります。

構造

ついでにどう動いているのか興味があったので、ちょっと自分なりに調べてみました。

CSS

答えとなる部分のクラスのCSSです。

.cp_qa .cp_actab .cp_actab-content {
    position: relative;
    overflow: hidden;
    max-height: 0;
    padding: 0 0 0 2.5em;
    -webkit-transition: max-height 0.2s;
         transition: max-height 0.2s;
    border-radius: 0 0 0.5em 0.5em;
}

答えとなるクラス.cp_qamax_heightが0となっており、初期状態では答えは表示されないのですが、

.cp_qa .cp_actab input:checked ~ .cp_actab-content {
    max-height: 40em;
    border: 10px solid rgba(27,37,56,0.1);
}

:checkedという擬似クラスセレクターを付加しmax-heightの値を40emに指定することで、「チェックを入れた時だけ高さを40emにする」という処理を行っているようです。

<div class="cp_actab">
  <input id="cp_tabfour031" type="checkbox" name="tabs">
  <label for="cp_tabfour031">質問テキスト</label>
  <div class="cp_actab-content">
  <p>答えテキスト</p>
  </div>
</div>

すなわち、この質問が書かれている部分は全体が「チェックボックス」という扱いになっています。(CSSで元のチェックボックス部分は隠すようになっています)

質問テキスト部分が書かれているところはlabelタグのfor属性の値をinputタグのidと一致させることで、inputタグと連携させています。(これはHTML5から追加された仕様のようです)

inputのidとlabelのforを同じid名に一致させないと、他の部分が開閉してしまう・動かないといった症状になるみたいです。質問と回答を追加したい場合も、同じくidforcp_tabfour0xx(xxは任意の数字)を指定してやると、うまく動きます。

まとめ

チェックボックスが押されたら」という疑似クラスセレクターが用意されていることを知りませんでした。 初めに自力で実装を考えたときは、display: none; で回答部分を見えなくし、JSのDOMでクリックしたら書き換える処理を考えていたのですが、確かにこちらのほうがCSSだけで済みますし、アニメーションもつけやすいですね。 ただし、このコードだと文字の表示にアニメーションが適用されていないので、高速でクリックをすると一瞬文字だけが先行して表示されているように見えてしまいます。これを解決するのを今後の課題とします。

参考にしたサイト