Open16

Web制作に役立つTipsを書き溜める ✨

Y.Y.

375px未満はviewportを固定する

画面幅が狭小な端末へのレスポンシブ対応は実装コストがかかるので、JSでviewportを書き換える。以下により375px未満のレスポンシブ対応が不要となる。

https://www.tak-dcxi.com/article/my-blogs-responsive-coding

const viewport = document.querySelector('meta[name="viewport"]')

/**
 * @description 375px以下のビューポートを固定
 */
export const viewportFix = () => {
  const value =
    window.outerWidth > 375 ? "width=device-width,initial-scale=1" : "width=375"
  if (viewport.getAttribute("content") !== value) viewport.setAttribute("content", value)
}

/**
 * @description ビューポートのサイズを取得する
 */
export const viewportSize = () => {
  const vw = window.innerWidth * 0.01
  const vh = window.innerHeight * 0.01

  document.documentElement.style.setProperty("--vw", `${vw}px`)
  document.documentElement.style.setProperty("--vh", `${vh}px`)
}

// debounce関数
const debounce = (func, delay) => {
  let timeoutId
  return (...args) => {
    clearTimeout(timeoutId)
    timeoutId = setTimeout(() => {
      func.apply(null, args)
    }, delay)
  }
}

const handleResize = debounce(() => {
  viewportSize()
  viewportFix()
}, 250) // 250ミリ秒の遅延時間を設定

window.addEventListener("resize", handleResize)
Y.Y.

コンテンツが100vh未満でもフッターを下に固定する

https://zenn.dev/catnose99/articles/a873bbbe25b15b

<div class="container">
    <header>ヘッダー</header>
    <main>メイン</main>
    <footer>フッター</footer>
</div>
.container {
  display: grid;
  grid-template-rows: auto 1fr auto;
  grid-template-columns: 100%;
  min-height: 100vh;
}
Y.Y.

タッチデバイスとクリックできない要素はhoverスタイルを無効にする

https://zenn.dev/kagan/articles/css-hover-style

hoverだけでは何が問題なのか

通常のhoverではスマホやタブレット等のタッチデバイスでもタッチした際もhover時のスタイルが適用されて、再度タッチするまでhoverスタイルが残り続けてしまう。

上記を回避するために下記のようにCSSを設定する。

@media (hover: hover) {
  a:hover {
    opacity: 0.7;
    transition: ease 0.3s;
  }
}

any-hoverでhoverに対応しているか判別する

ただ、上記ではタブレットでキーボード等を接続して使用している場合にhoverが適用されなくなる。
any-hoverを使用することで端末がhoverに対応しているか(タブレットでキーボードが接続されているか)を判別できるようになるので、基本はany-hoverでホバーのスタイルを設定する。

@media (any-hover: hover) {
  a:hover {
    opacity: 0.7;
    transition: ease 0.3s;
  }
}

クリック可能な要素にだけhoverスタイルを適用する

  • :any-link
    カレントページに該当するパンくずリストなどはhref属性が空になるためこのような要素はhoverスタイルを適用させない

  • :enabled
    カルーセルの最後のスライドに達した時、「次へ」のボタンが<button disabled>になっているとき、hoverスタイルを適用させない

  • :where(summary)
    summary要素はhoverスタイルを適用させる

全部まとめる

下記のようにCSSを設定すると、デバイスがhoverをサポートしている、aタグにリンクがある、disabled属性が設定されていない<button><input>タグ、summary要素に対してhoverスタイルが適用されるようになる。

 @media (any-hover: hover) {
    .hover-element:where(:any-link, :enabled, summary):hover {
        background-color: blue;
    }
}

Sassでmixinにしておく

_variables.scss
@mixin hover {
  @media (any-hover: hover) {
    &:where(:any-link, :enabled, summary):hover {
      @content;
    }
  }
}
style.scss
@use "../mixin/_variables" as *;

.link {
  color: #000;

  @include hover {
    color: #3ea8ff;
  }
}
Y.Y.

インラインSVGのマークアップ

下記の実装だとaria-labelの中身は翻訳されない。

<svg role="img" aria-label="画像の説明">
    ...
</svg>

ベストプラクティスは、<svg>aria-hidden="true"を指定して、スクリーンリーダーなどの支援技術が読み上げないようにし、<span>タグでスクリーンリーダー用のテキストを設置する。

<svg aria-hidden="true">
    ...
</svg>
<span class="sr-only">画像の説明</span>
Y.Y.

<span>タグでテキストを1文字ずつアニメーションさせる時は翻訳させないようにする

1文字ごとテキストをアニメーションさせるときに<sapn>タグで囲むが、これだと適切な翻訳がされないので、親要素にtranslate="no"属性を付与して翻訳対象から外しておく。

<div tranlate="no">
    <span></span><span></span><span></span><span></span>
</div>
<span class="sr-only">テキスト</span>
Y.Y.

Google fontsの最適化

「Flash Of Unstyled Text」を防ぐ方法。

{href}の箇所にGoogle fontsで生成されるURLを入れる。
上2つのコードはGoogle fontsから出力されるコードの一部。

<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="preload" as="style" fetchpriority="high" href="Google fontsから出力されるURLを入れる" />
<link rel="stylesheet" href="{href}" media="print" onload='this.media="all"' />

rel="preload"fetchpriority="high"

Google Fontsのスタイルシートを事前に読み込むように指示し、Webページの描画が行われる前にフォントを利用可能にして表示速度を上げる。

media="print"onload='this.media="all"

media="print"を指定して印刷用のCSSだとブラウザを騙して現在のレンダリングと関係なく読み込みさせる。

onloadイベントが発火した(フォントの読み込みが完了した)時に、this.media="all"とすることで初めてWebページにフォントが適応されるという仕組み。

https://css-tricks.com/how-to-load-fonts-in-a-way-that-fights-fout-and-makes-lighthouse-happy/

Y.Y.

iOSにおけるbutton要素の連続タップによるズーム対策

:where(button, [type='button'], [type='reset'], [type='submit']) {
  touch-action: manipulation;
}
Y.Y.

長いテキストを3点リーダーで省略する実装方法

.titleがdisplay: block;である必要がある。

/* 1行を超えたら3点リーダー */
.title {
    overflow-x: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}