ホームページ > ウェブフロントエンド > CSSチュートリアル > getComputedStyle: 良い部分、悪い部分、醜い部分

getComputedStyle: 良い部分、悪い部分、醜い部分

WBOY
リリース: 2024-07-28 10:42:23
オリジナル
767 人が閲覧しました

getComputedStyle は他に類を見ないものです。バックグラウンドでいくつかの興味深いことを実行し、独自のユニークな使用方法を持っています。この投稿では、このほろ苦い API に関する私の経験と考えを共有します。

最近この機能をよく使うので、私自身もこの投稿を編集するつもりです。また、ニッチなケースもたくさんあると思います。ちなみに、この投稿の最後に、私の旅に役立ったリンクをいくつか載せておきます。

getComputedStyle とは何ですか?

MDN から直接:

Window.getComputedStyle() メソッドは、アクティブなスタイルシートを適用し、それらの値に含まれる可能性のある基本的な計算を解決した後、要素のすべての CSS プロパティの値を含むオブジェクトを返します。

個々の CSS プロパティ値には、オブジェクトによって提供される API を介してアクセスするか、CSS プロパティ名でインデックスを作成することによってアクセスします。

プレーンな JavaScript での使用例:

const element = document.getElementById("#box");

// Get the computed styles of an element
const styles = getComputedStyle(element);
ログイン後にコピー

簡単に言えば、指定された要素のスタイルを返します。ここで興味深いのは、計算の解決です。 CSS で calc():
を使用して width プロパティを指定したとします。

#box {
  width: calc(100px - 80px);
}
ログイン後にコピー

結果として 20px が得られます。つまり、実際に JavaScript から CSS 計算の結果にアクセスできるということです。ビューポートやパーセント単位 (100vh、50% など) も計算し、結果をピクセル単位で返します。すごい!

注意点: 計算された値はプロパティに依存しており、静的ではありません。つまり、次のような計算は期待できません:

#box {
  --box-width: calc(100px - 80px);
  width: var(--box-width);
}
ログイン後にコピー
// boxWidth variable will be set to string `calc(100px - 80px)`
// Not `20px`
const boxWidth = getComputedStyle(element)["--box-width"];
ログイン後にコピー

CSS 変数の結果を静的に計算することは不可能なので、これは完全に理にかなっています。それは環境と財産の側面によって異なります (たとえば、パーセンテージを考えてください)。

ただし、width プロパティにアクセスしようとすると、20 ピクセルが必要になります。最終的には特定の要素の幅を計算することになります:

// 20px
const { width } = getComputedStyle(element);
ログイン後にコピー

それは素晴らしいことですが、実際の使用例は何ですか?

要素を 0px から auto に移行する

calc-size() が最新のブラウザで広く利用可能になった後にこの投稿を読んでいる場合は、それをやめて使用してください。おそらくここでのソリューションよりも優れたパフォーマンスを発揮するでしょう。自動に移行できない現実に行き詰まっている場合は、そのまま続行してください!

Web 開発の過程で、自動へのアニメーション化や自動からのアニメーション化に何度か遭遇したことがあるかもしれません。アニメーション ライブラリはここに適しているかもしれませんが、まったく必要ないと言ったらどうしますか?

オン/オフを切り替えることができるテキスト コンテンツを含むボックスがあるとします。テキストの内容は動的であるため、事前に最大高さを指定することはできません。ああ、デザイナーはそこにアニメーションも必要としているので、0px から自動高さまでゆっくりと移行する必要があります。

以下は HTML と CSS になります:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  </head>
  <style>
    #box {
      position: relative;
      display: block;
      width: fit-content;
      height: 0px;
      overflow: hidden;
      background-color: rebeccapurple;
      color: whitesmoke;
      transition: 1s;
    }
  </style>
  <body>
    <button type="button" id="toggle">toggle</button>
    <div id="box"></div>

    <script type="module" src="/src/main.ts" defer></script>
  </body>
</html>
ログイン後にコピー

スクリプト側では、最初はあまり何もしません。テキストコンテンツを配置または削除するための単純な状態を維持する必要があるだけです。 (TS を使用するかどうかはあなた次第です):

// get the wrapper div
const box = document.getElementById("box") as HTMLDivElement;
// get the trigger button
const button = document.getElementById("toggle") as HTMLButtonElement;
// state that keeps track
let toggle = false;

function changeBoxContent() {
  if (toggle) {
    box.innerText = `Lorem ipsum dolor sit, 
    amet consectetur adipisicing elit.
    Minima culpa ipsum quibusdam quia
    dolorum excepturi sequi non optio,
    ad eaque? Temporibus natus eveniet
    provident sit cum harum,
    praesentium et esse?`;
  } else {
    box.innerText = "";
  }
}

button.addEventListener("click", () => {
  // flip the toggle
  toggle = !toggle;
  // update the content
  changeBoxContent();

  // ...
});
ログイン後にコピー

ここでのコードは、ボックスの innerText を疑似文字列に設定するか、空の文字列に戻すだけです。

ここでボタンをクリックしても、何も変わっていないことがわかります。これは、ボックスの高さを 0 ピクセルに設定し、オーバーフローを非表示にしているためです。

テキストに必要なスペースを知るには、ボックスの高さを auto に設定し、ボックスで getComputedStyle を呼び出します。ここでの考え方は、要素を自動で必要なだけ拡大させ、getComputedStyle がそのサイズをピクセル単位で取得することです。

button.addEventListener("click", () => {
  // flip the toggle
  toggle = !toggle;
  // update the content
  changeBoxContent();

  // set the element's height to `auto`, this enlarges the element to fit it's content
  box.style.height = "auto";

  // we got our desired height property!
  const height = getComputedStyle(box).height;

  console.log(height);
});
ログイン後にコピー

ボタンをクリックすると、ボックスが必要な高さになっていることがわかります。コンソールで高さをピクセル単位で確認することもできます:

Result A1

それは素晴らしいことですが、確実に移行するわけではありません。

必要な高さがわかっているので、ボックスの高さを元の位置に戻すことができるかもしれません。 requestAnimationFrame の呼び出し内で、getComputedStyle から取得した高さに設定できます。試してみましょう!

button.addEventListener("click", () => {
  // flip the toggle
  toggle = !toggle;
  // update the content
  changeBoxContent();

  // set the element's height to `auto`, this enlarges the element to fit it's content
  box.style.height = "auto";

  // we got our desired height property!
  const height = getComputedStyle(box).height;

  // set the height back to where it was (0px)
  box.style.height = "";

  // set the final height in next animation frame
  requestAnimationFrame(() => {
    box.style.height = height;
  });
});
ログイン後にコピー

高さを 0px に設定し、次のアニメーション フレームで変更するとわかっているので、アニメーションが表示されるはずですよね?

そうですね、正確にはそうではありません。これをハイエンド PC の Chrome で実行している場合は、遷移アニメーションを観察する必要がありますが、ローエンド PC や一部のブラウザ (Firefox など) では、何も変化していないことがわかります。

私のコンピューター上の Firefox と Chrome の比較:

getComputedStyle: The good, the bad and the ugly parts

これが起こる理由は、レイアウトの計算がスタイルの後に行われるためです。レイアウトの計算がスタイルの計算の前に行われることは保証できません。また、ブラウザによっては requestAnimationFrame の実装も異なるようです。 (詳しくはこちらをご覧ください)

Don't get into despair though! We have multiple solutions for this. We can:

  • Force the browser to run layout calculations immediately before styles
  • Use intertwined requestAnimationFrames to make sure the animation will be run on the next tick (also known as double rAF())

Let's try forcing the browser to calculate styles first. Remember getComputedStyle? I'm sure you do. It'll come to our rescue here too!

Right after we set height back to 0px, we'll force to recalculate the layout:

button.addEventListener("click", () => {
  // flip the toggle
  toggle = !toggle;
  // update the content
  changeBoxContent();

  // set the element's height to `auto`, this enlarges the element to fit it's content
  box.style.height = "auto";

  // we got our desired height property!
  const height = getComputedStyle(box).height;

  // set the height back to where it was (reset)
  box.style.height = "";

  // we're synchronously forcing the browser to recalculate the height of the element
  getComputedStyle(box).height;

  // set the final height in next animation frame
  requestAnimationFrame(() => {
    box.style.height = height;
  });
});
ログイン後にコピー

GOTCHA: You might be thinking why we're accessing height property but not assigning it to anything. Well that's because getComputedStyle computes a property on access. It's actually to make it more optimized, it'll only run layout calculations on access to top, left, bottom, right, width and height. Its not documented but good to keep in mind. Try changing it to getComputedStyle(box), you'll see nothing has changed.

So that was one way to solve it and honestly I like this way much better. It's good to know double rAF() trick too, though.

For that we simply need to wrap our requestAnimationFrame with another requestAnimationFrame:

button.addEventListener("click", () => {
  // flip the toggle
  toggle = !toggle;
  // update the content
  changeBoxContent();

  // set the element's height to `auto`, this enlarges the element to fit it's content
  box.style.height = "auto";

  // we got our desired height property!
  const height = getComputedStyle(box).height;

  // set the height back to where it was (reset)
  box.style.height = "";

  // set the final height in next animation frame
  requestAnimationFrame(() => {
    requestAnimationFrame(() => {
      box.style.height = height;
    });
  });
});
ログイン後にコピー

Think of it like in the next frame, we've queued an animation that'll run on the next frame. I know it sounds weird but that used to solve lots of problems since it has a bug in Chrome too.

That's the wrap! As you can see in a modern world where we have WAAPI, transitions and getComputedStyle still have their use! It's a bit nasty to understand at start but it has it's own way of doing things, what can I say!

Sources:
Transition to Height Auto With Vue.js by Markus Oberlehner
Need cheap paint? Use getComputedStyle().opacity by Webventures

以上がgetComputedStyle: 良い部分、悪い部分、醜い部分の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート