HTML <details> の open 属性はCSSメディアクエリで制御できない
ブログの目次を <details> で実装していて、デスクトップでは開いた状態、モバイルでは閉じた状態にしたかった。CSSの @media で open 属性を切り替えられると思ったが、open はHTML属性であってCSSプロパティではないため不可能だった。
React での解決策はシンプルで、useEffect でマウント時にウィンドウ幅を判定する。
const [isOpen, setIsOpen] = useState(true);
useEffect(() => {
setIsOpen(window.innerWidth >= 768);
}, []);
return (
<details
open={isOpen}
onToggle={(e) => setIsOpen(e.currentTarget.open)}
>
<summary>目次</summary>
{/* ... */}
</details>
);onToggle でユーザーの手動開閉も追跡するのがポイント。SSR時は true(開いた状態)でレンダリングされ、クライアントでモバイルなら閉じるという流れになる。
