質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

CSS

CSSはXMLやHTMLで表現した色・レイアウト・フォントなどの要素を指示する仕様の1つです。

Q&A

解決済

1回答

1389閲覧

jQueryのslideToggleを素のJavaScriptで実装したときに、el.offsetHeight; という記述がないとアニメーションが引き起こされない理由をご享受ください。

uidev1116

総合スコア1

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

CSS

CSSはXMLやHTMLで表現した色・レイアウト・フォントなどの要素を指示する仕様の1つです。

0グッド

1クリップ

投稿2021/11/21 04:18

前提・実現したいこと

Convert Jquery slidetoggle code to Javascript内にある2つ目の回答を参考に、素のJavaScriptでjQueryの slideToggle() 関数を以下のように実装しました。

js

1export const slideUp = (el, duration = 300) => { 2 const { style, offsetHeight } = el; 3 style.height = `${offsetHeight}px`; 4 style.transitionProperty = "height, margin, padding"; 5 style.transitionDuration = `${duration}ms`; 6 style.transitionTimingFunction = "ease"; 7 style.boxSizing = "border-box"; 8 style.overflow = "hidden"; 9 el.offsetHeight; // ←ここです。 10 style.height = 0; 11 style.paddingTop = 0; 12 style.paddingBottom = 0; 13 style.marginTop = 0; 14 style.marginBottom = 0; 15 setTimeout(() => { 16 style.display = "none"; 17 style.removeProperty("height"); 18 style.removeProperty("padding-top"); 19 style.removeProperty("padding-bottom"); 20 style.removeProperty("margin-top"); 21 style.removeProperty("margin-bottom"); 22 style.removeProperty("overflow"); 23 style.removeProperty("transition-duration"); 24 style.removeProperty("transition-property"); 25 style.removeProperty("transition-timing-function"); 26 }, duration); 27}; 28 29export const slideDown = (el, duration = 300) => { 30 const { style } = el; 31 32 style.removeProperty("display"); 33 let { display } = getComputedStyle(el); 34 if (display === "none") { 35 display = "block"; 36 } 37 style.display = display; 38 39 const { offsetHeight } = el; 40 style.height = 0; 41 style.paddingTop = 0; 42 style.paddingBottom = 0; 43 style.marginTop = 0; 44 style.marginBottom = 0; 45 style.overflow = "hidden"; 46 style.boxSizing = "border-box"; 47 el.offsetHeight; // ←ここです。 48 style.transitionProperty = "height, margin, padding"; 49 style.transitionDuration = `${duration}ms`; 50 style.transitionTimingFunction = "ease"; 51 style.height = `${offsetHeight}px`; 52 style.removeProperty("padding-top"); 53 style.removeProperty("padding-bottom"); 54 style.removeProperty("margin-top"); 55 style.removeProperty("margin-bottom"); 56 setTimeout(() => { 57 style.removeProperty("height"); 58 style.removeProperty("overflow"); 59 style.removeProperty("transition-duration"); 60 style.removeProperty("transition-property"); 61 style.removeProperty("transition-timing-function"); 62 }, duration); 63}; 64 65export const slideToggle = (el, duration = 300) => { 66 if (getComputedStyle(el).display === "none") { 67 return slideDown(el, duration); 68 } 69 return slideUp(el, duration); 70};

発生している問題

上記のソースコード内で、"ここです。" というコメントがされている el.offsetHeight; の記述が、style.height = ${offsetHeight}px;style.height = 0 の間にない場合は、スライドのアニメーションが引き起こされません。この理由についてご教授いただきたく思い、質問させていただきました。

ここからは推測の話になりますが、おそらく、el.offsetHeight; の部分で 強制同期レイアウトの回避で紹介されているような Forced Synchronous Layout(強制同期レイアウト)が引き起こされ、ブラウザのレンダリングエンジンがレイアウト計算を行うことで、ブラウザのレンダリングエンジンが1つ目の style.height = の処理で指定した高さの値を理解し、2つ目のstyle.height = の処理でアニメーションが引き起こされるのではないかと思っています。

つまり、el.offsetHeight; の記述がない場合は、Forced Synchronous Layout(強制同期レイアウト)が引き起こされず、1つ目の style.height = の処理と、2つ目のstyle.height = の処理の間でブラウザがレイアウト情報を更新することなく style.height の値がへんこうされるため、ブラウザのレンダリングエンジンにとっては 要素の高さが1度しか更新されていないと判断してアニメーションが引き起こされないのではないかと考えています。

上記の考えが合っているのかどうか、間違っている場合はなぜアニメーションが引き起こされないのかというところをご教授いただけると幸いです。

該当のソースコード

codesandboxに検証環境を用意しました。よろしければフォークして検証などに利用していただけると幸いです。

https://codesandbox.io/s/playground-for-slidetoggle-06pwu?file=/src/slideToggle.js

試したこと

offsetHeight だけでなく、レイアウトの情報を返すメソッドやプロパティである、offsetWidthoffsetTopclientHeight でも同様の現象が起きました。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

上記の考えが合っているのかどうか

そのとおりかと思います。

投稿2021/11/21 05:22

maisumakun

総合スコア146018

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

uidev1116

2021/11/23 06:25

ご回答ありがとうございました。!強制リフローとも言って、パフォーマンス的には悪いことだと思っていましたが、こんな使い方もあるとしれたので良かったです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問