目次
まず、フラグを有効にします
いくつかのマークアップから始めましょう
それでは、いくつかのスタイルを適用しましょう
JavaScriptフォールバックソリューション
いくつかの小さな改善
より現実的な構造
最初の要素をメッシュに及ぼします
さまざまなアスペクト比のグリッドアイテムを処理します
しかし、しかし、しかし...
ブラウザのサポートはどうですか?
JavaScriptのない状況はどうですか?

軽量の石積みソリューション

Apr 03, 2025 am 10:06 AM

軽量の石積みソリューション

5月に、FirefoxがCSSグリッドに石積みレイアウト機能を追加したことを知りました。石積みのレイアウトは、私がいつもゼロから実装したかったものですが、どこから始めればいいのかわかりません。だから私は自然にデモを見て、この新しいCSS機能がどのように機能するかを理解したとき、インスピレーションの閃光がありました。

現在、サポートはFirefoxに限定されています(そして、特定のフラグが有効になっている場合のみ)が、これにより、現在サポートがないブラウザをカバーできるJavaScriptの実装の出発点が得られます。

Firefoxはgrid-template-rows (例に示す)またはgrid-template-columns masonry値に設定することにより、CSSの石積みレイアウトを実装します。

私のアプローチは、この機能を活用してブラウザをサポートし(繰り返しますが、今のところFirefoxのみを指します)、ブラウザの残りのためにJavaScriptフォールバックスキームを作成することです。画像グリッドの特定のケースを使用してこれを達成する方法を見てみましょう。

まず、フラグを有効にします

これを行うには、Firefoxのabout:configと「Masonry」を検索します。これによりlayout.css.grid-template-masonry-value.enabledフラグが表示されます。これは、 false (デフォルト値)からtrueにダブルクリックすることで有効にできます。

いくつかのマークアップから始めましょう

HTML構造は次のとおりです。

<img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/000/174364597525146.jpg" class="lazy" alt="軽量の石積みソリューション">
ログイン後にコピー

それでは、いくつかのスタイルを適用しましょう

まず、最上位要素をCSSグリッドコンテナとして設定します。次に、画像の最大幅、たとえば10emを定義します。また、これらの画像がグリッドコンテンツボックスで利用可能な任意のスペースに収縮したいと考えています。ビューポートが狭くなりすぎて10em列グリッドを収容できない場合、実際に設定された値はMin(10em, 100%)です。レスポンシブデザインは最近では非常に重要であるため、固定数の列を使用する代わりに、この幅の幅をできるだけ多くの列を自動的に適応させます。

 $ w:min(10em、100%);

.grid  -  masonry {
  ディスプレイ:グリッド;
  Grid-Template-Columns:Repeat(auto-fit、$ w);

  > * {width:$ w; }
}
ログイン後にコピー

SASSの競合を避けるために、min Min() min() )を使用したことに注意してください。

わかりました、これはグリッドです!

しかし、それはあまり素晴らしいグリッドではないので、その内容を強制的に水平方向に中心にしてから、間隔値( $s )に等しいグリッドギャップと塗りつぶしを追加しましょう。また、視聴を容易にするための背景を設定します。

 $ s:.5em;

/*石積みグリッドスタイル*/
.grid  -  masonry {
  /*以前のスタイルと同じ*/
  justify-content:center;
  グリッドギャップ:$ s;
  パディング:$ s;
}

/*美化スタイル*/
html {背景:#555; }
ログイン後にコピー

グリッドを少し美化した後、グリッドプロジェクト(つまり、画像)についても同じことをすることになりました。フィルターを適用して、少し丸い角と影のある追加のスタイルを追加しながら、もう少し均一に見せてみましょう。

 img {
  ボーダーラジウス:4px;
  Box-Shadow:2PX 2PX 5PX RGBA(#000、.7);
  フィルター:セピア(1);
}
ログイン後にコピー

ここで、石積みのレイアウトをサポートするブラウザの場合、それを宣言する必要があります。

 .grid  -  masonry {
  /*以前のスタイルと同じ*/
  グリッドテンプレート列:巨大な;
}
ログイン後にコピー

これはほとんどのブラウザでは機能しませんが、FirefoxではFirefoxで説明されています。

しかし、他のブラウザはどうですか?これが私たちが必要とするものです...

JavaScriptフォールバックソリューション

ブラウザが実行する必要があるJavaScriptコードを保存するために、最初に.grid--masonry要素があるかどうか、およびブラウザがgrid-template-rowsmasonry値を理解および適用したかどうかを確認します。これは一般的なアプローチであることに注意してください。これは、ページにそのようなメッシュが複数ある可能性があると仮定しています。

 let grids = [... document.queryselectorall('。grid -  masonry ')];

if(grids.length && getComputedStyle(grids [0])。gridtemplaterows!== 'masonry'){
  console.log( 'oops、masonryレイアウトはサポートしませんか?');
} それ以外 {
  console.log( '良すぎる、操作は不要!');
}
ログイン後にコピー

新しい石積み機能がサポートされていない場合、各石積みメッシュの行ギャップとメッシュアイテムが取得され、列の数を設定します(各メッシュは最初は0です)。

 let grids = [... document.queryselectorall('。grid -  masonry ')];

if(grids.length && getComputedStyle(grids [0])。gridtemplaterows!== 'masonry'){
  grids = grids.map(grid =>({
    _el:グリッド、
    ギャップ:parsefloat(getComputedStyle(grid).gridrowgap)、
    アイテム:[... grid.childnodes] .filter(c => c.nodetype === 1)、
    NCOL:0
  }));

  grids.foreach(grid => console.log( `grid item:$ {grid.items.length}; grid gap:$ {grid.gap} px`));
}
ログイン後にコピー

子ノードが要素ノードであることを確認する必要があることに注意してください(これは、 nodeTypeが1であることを意味します)。それ以外の場合は、プロジェクトアレイ内のキャリッジリターンで構成されるテキストノードになってしまう可能性があります。

進む前に、ページがロードされ、要素がまだ動いていることを確認する必要があります。この問題に対処したら、各グリッドを取り、現在の列数を読み取ります。これがすでに持っている値と異なる場合は、古い値を更新し、グリッドアイテムを再配置します。

 if(grids.length && getComputedStyle(grids [0])。gridtemplaterows!== 'masonry'){
  grids = grids.map(/*は以前と同じ*/);

  function layout(){
    grids.foreach(grid => {
      /*サイズ/ロードされた列番号を取得*/
      let ncol = getComputedStyle(grid._el).gridtemplatecolumns.split( '').length;

      if(grid.ncol!== ncol){
        grid.ncol = ncol;
        console.log( 'グリッドアイテムの再配置');
      }
    });
  }

  addeventListener( 'load'、e => {
    レイアウト(); /*初期負荷*/
    addeventListener( 'resize'、layout、false);
  }、 間違い);
}
ログイン後にコピー

layout()関数を呼び出すことは、初期負荷とサイズ変更の両方の場合に実行する必要がある操作であることに注意してください。

グリッドアイテムを再配置するための最初のステップは、すべてのアイテムから上限を削除することです(これは、現在のサイズ変更前に石積み効果を達成するために非ゼロ値に設定できます)。

ビューポートが十分に狭く、列が1つしかない場合は、完了です!

それ以外の場合は、最初のncolアイテムをスキップして、残りをループします。考慮された各アイテムについて、上記のアイテムのボトムエッジ位置と上端の現在の位置を計算します。これにより、上端が上記のプロジェクトの下端の下のグリッドギャップにあるように、必要な垂直方向の動きの量を計算できます。

 /*列の数が変更された場合*/
if(grid.ncol!== ncol){
  /*更新された列の数*/
  grid.ncol = ncol;

  /*初期位置決めを復元する、境界線なし*/
  grid.items.foreach(c => c.style.RemoveProperty( 'marve-top'));

  /*複数の列がある場合*/
  if(grid.ncol> 1){
    grid.items.slice(ncol).foreach((c、i)=> {
      prev_fin = grid.items [i] .getBoundingClientRect()。下、 /*上記のプロジェクトのボトムエッジ* /
          curr_ini = c.getBoundingClientRect()。top; /*現在のプロジェクトの最上端*/

      c.style.margintop = `$ {prev_fin grid.gap -curr_ini} px`;
    });
  }
}
ログイン後にコピー

これで、作業クロスブラウザーソリューションがあります!

いくつかの小さな改善

より現実的な構造

現実の世界では、各画像をフルサイズの画像にリンクに巻き付ける可能性が高く、大きな画像をライトボックスに開くことができます(または、フォールバックとしてナビゲートします)。

<a href="https://www.php.cn/link/849c1f472f609bb4a3bacafef177f541">
  <img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/000/174364597550777.jpg" class="lazy" alt="軽量の石積みソリューション">
</a>
ログイン後にコピー

これは、CSSを少し変更する必要があることを意味します。グリッドアイテムの幅を明示的に設定する必要はなくなりましたが、リンクがリンクになっているため、 align-self: start必要があります。画像とは異なり、デフォルトでは行の高さ全体をカバーし、アルゴリズムを乱すためです。

 .grid  -  masonry> * {align-self:start; }

img {
  表示:ブロック; /*下部の奇妙な余分なスペースを避けます*/
  幅:100%;
  /*以前のスタイルと同じ*/
}
ログイン後にコピー

最初の要素をメッシュに及ぼします

また、最初のプロジェクトをメッシュ全体に水平に及ぼすこともできます(つまり、おそらくその高さを制限し、画像がオーバーフローまたは変形しないようにする必要があります):

 .grid  -  masonry>:first-child {
  グリッドコラム:1 / -1;
  Max-Height:29VH;
}

img {
  max-height:継承;
  オブジェクトフィット:カバー;
  /*以前のスタイルと同じ*/
}
ログイン後にコピー

また、グリッドアイテムのリストを取得して、この伸縮したアイテムを除外するときに、別のフィルターを追加する必要があります。

 grids = grids.map(grid =>({
  _el:グリッド、
  ギャップ:parsefloat(getComputedStyle(grid).gridrowgap)、
  アイテム:[... grid.childnodes] .filter(c =>
    c.nodeType === 1 &&
     getComputedStyle(c).gridcolumnend!== -1
  )、、
  NCOL:0
}));
ログイン後にコピー

さまざまなアスペクト比のグリッドアイテムを処理します

ブログなどの目的にこのソリューションを使用したいとします。まったく同じJSとほぼ同一の石積み固有のCSSを保持します。列の最大幅を変更し、最初のアイテムのmax-height制限を削除するだけです。

以下のデモからわかるように、この場合はソリューションが完全に機能し、ブログ投稿グリッドがあります。

ビューポートのサイズを変更して、この場合にどのように機能するかを確認することもできます。

ただし、たとえば、列の幅をある程度の柔軟性にしたい場合は、

 $ w:minmax(min(20em、100%)、1fr);
ログイン後にコピー

その後、サイズを変更する際に問題が発生します。

グリッドアイテムの幅の変更と、各アイテムのテキストコンテンツが異なるという事実の組み合わせは、特定のしきい値を超えた場合、グリッドアイテムのテキスト行の数が異なる場合(したがって高さを変更する)ことを意味しますが、他のアイテムはそうではありません。列の数が変更されていない場合、垂直オフセットは再計算されず、オーバーラップまたは大きなギャップになります。

この問題を解決するには、少なくとも1つのアイテムの現在のグリッドの高さが変更されたときにオフセットを再計算する必要があります。つまり、現在のグリッドにゼロ以上のアイテムが高さを変えたかどうかをテストする必要があります。次に、 ifブロックの最後にこの値をリセットする必要があります。そうすれば、次回アイテムを不必要に再配置する必要がないようにする必要があります。

 if(grid.ncol!== ncol || grid.mod){
  /*以前と同じ*/
  grid.mod = 0;
}
ログイン後にコピー

わかりましたが、このgrid.mod値をどのように変更しますか?私の最初のアイデアは、 ResizeObserver使用することです。

 if(grids.length && getComputedStyle(grids [0])。gridtemplaterows!== 'masonry'){
  let o = new resizeObserver(entries => {
    entries.foreach(entry => {
      grids.find(grid => grid._el === entry.target.parentelement).mod = 1;
    });
  });

  /*以前と同じ*/

  addeventListener( 'load'、e => {
    /*以前と同じ*/
    grids.foreach(grid => {grid.items.foreach(c => o.observe(c));});
  }、 間違い);
}
ログイン後にコピー

これにより、グリッド列の数​​が変更されていない場合でも、必要に応じてグリッドアイテムを再配置できます。しかし、条件が利用できないifでも、それは無意味になります!

これは、少なくとも1つのアイテムの高さまたは幅が変更されたときにgrid.modが1に変更されるためです。プロジェクトの高さは、幅の変化によって引き起こされるテキストリフローのために変化します。ただし、ビューポートサイズを調整するたびに幅の変化が発生し、必ずしも高さの変化をトリガーするわけではありません。

そのため、以前のプロジェクトの高さを保存し、 grid.mod 0に残っているかどうかを判断するために変更されたときに変更されたかどうかを確認することにしました。

 function layout(){
  grids.foreach(grid => {
    grid.items.foreach(c => {
      new_h = c.getBoundingClientRect()。height;

      if(new_h!== c.dataset.h){
        c.dataset.h = new_h;
        grid.mod;
      }
    });

    /*以前と同じ*/
  });
}
ログイン後にコピー

それでおしまい!今、私たちは素敵な軽量ソリューションを持っています。圧縮されたJavaScriptは800バイト未満ですが、厳密な石積み関連のスタイルは300バイト未満です。

しかし、しかし、しかし...

ブラウザのサポートはどうですか?

さて、 @supports 、ここで使用されている新しいCSS機能よりも優れたブラウザのサポートを持っているため、良いものを入れて、サポートされていないブラウザに基本的な非整形メッシュを提供できます。このバージョンは、IE9と後方互換性があります。

見た目が違うかもしれませんが、見た目が良く、完璧な機能を備えています。ブラウザをサポートすることは、すべての視覚効果をコピーすることを意味しません。これは、ページが機能し、損傷したりugいたりしないように見えることを意味します。

JavaScriptのない状況はどうですか?

まあ、ルート要素にJavaScriptを介して追加したjsクラスがある場合にのみ、派手なスタイルを適用できます!それ以外の場合は、すべてのアイテムに対して同じサイズのベースグリッドを取得します。

以上が軽量の石積みソリューションの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

GraphQLキャッシングの使用 GraphQLキャッシングの使用 Mar 19, 2025 am 09:36 AM

最近GraphQLの作業を開始した場合、またはその長所と短所をレビューした場合、「GraphQLがキャッシュをサポートしていない」または

Redwood.jsと動物相を使用してイーサリアムアプリを構築します Redwood.jsと動物相を使用してイーサリアムアプリを構築します Mar 28, 2025 am 09:18 AM

最近のビットコインの価格が20k $ $ USDを超えており、最近30Kを破ったので、イーサリアムを作成するために深く掘り下げる価値があると思いました

Eleventyで独自のBragdocを作成します Eleventyで独自のBragdocを作成します Mar 18, 2025 am 11:23 AM

開発者としての段階に関係なく、私たちが完了したタスクは、大小を問わず、個人的および専門的な成長に大きな影響を与えます。

Vue 3 Vue 3 Apr 02, 2025 pm 06:32 PM

それは&#039; Vueチームにそれを成し遂げてくれておめでとうございます。それは大規模な努力であり、長い時間がかかったことを知っています。すべての新しいドキュメントも同様です。

ブラウザから有効なCSSプロパティ値を取得できますか? ブラウザから有効なCSSプロパティ値を取得できますか? Apr 02, 2025 pm 06:17 PM

私はこの非常に正当な質問で誰かに書いてもらいました。 Leaは、ブラウザから有効なCSSプロパティ自体を取得する方法についてブログを書いています。それはこのようなものです。

CI/CDで少し CI/CDで少し Apr 02, 2025 pm 06:21 PM

「ウェブサイト」は「モバイルアプリ」よりも適していると言いますが、Max Lynchからのこのフレーミングが好きです。

レスポンシブデザインのブラウザを比較します レスポンシブデザインのブラウザを比較します Apr 02, 2025 pm 06:25 PM

これらのデスクトップアプリがいくつかあり、目標があなたのサイトをさまざまな次元ですべて同時に表示しています。たとえば、書くことができます

粘着性のあるポジショニングとサスのダッシュを備えた積み重ねられたカード 粘着性のあるポジショニングとサスのダッシュを備えた積み重ねられたカード Apr 03, 2025 am 10:30 AM

先日、Corey Ginnivanのウェブサイトから、この特に素敵なビットを見つけました。そこでは、スクロール中にカードのコレクションが互いに積み重ねられていました。

See all articles