web-dev-qa-db-ja.com

CSSを使用して、「B」の幅とテキストの折り返しが不明な「B」の下端/端に「A」を「ぴったり」配置する方法

現在ソートされている列のヘッダーにアイコンが表示される「ソート可能な」テーブルがあります。

enter image description here

ソートアイコンはテキストのendに表示されます(つまり、LTR/RTLをサポートしています)。現在、display:flexを使用しています。ただし、テーブルの幅が小さくなり、列ヘッダーのテキストが折り返され始めると、並べ替えられている列が明確でないあいまいな状態になります。

enter image description here

代わりに、次の要件を満たしたいと思います。

  1. アイコンは常に「最後」に「ぴったり」と位置合わせされますテキストの最も長い行の(ラッピングセル/ボタンの幅が広い場合でも)。
  2. アイコンは、テキストの最後の行と下揃えにする必要もあります。
  3. アイコンはそれ自体の行に折り返してはなりません。
  4. ボタンが存在し、セルの幅全体に及ぶ必要があります。 (内部のスタイル設定であり、マークアップは必要に応じて変更できます。)
  5. CSSとHTMLは、可能な場合のみ。
  6. 既知の/設定された列幅やヘッダーテキストに依存することはできません。

例えば:

enter image description here

display: inline/inline-block/flex/gridposition::before/::after、さらにはfloat(!)のさまざまな組み合わせを試してみましたが、望ましい動作を得ることができません。これが問題を示す私の現在のコードです:

.table {
  border-collapse: collapse;
  width: 100%;
}

.thead {
  border-bottom: 3px solid #d0d3d3;
}

.thead .tr {
  vertical-align: bottom;
}

.button {
  padding: 1rem;
  text-align: start;
  font-family: Arial, "noto sans", sans-serif;
  font-size: 0.875rem;
  border: 0;
  background-color: transparent;
  width: 100%;
  display: flex;
  align-items: flex-end;
  font-weight: bold;
  line-height: 1.4;
}

.sort {
  width: 1.25rem;
  height: 1.25rem;
}
<table class="table">
  <thead class="thead">
    <tr class="tr">
      <th class="th">
        <button class="button">
          Age
          <span class="sort"></span>
         </button>
      </th>
      <th class="th">
        <button class="button">
          Favorite Food
          <span class="sort"></span>
        </button>
      </th>
      <th class="th" aria-sort="ascending">
        <button class="button">
          Favorite Color
          <span class="sort">
            <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" role="presentation" style="width: 1.25rem; height: 1.25rem;"> <path d="M11.4709 4.2136C11.7638 3.92071 12.2386 3.92071 12.5315 4.2136L17.1277 8.8098C17.4206 9.10269 17.4206 9.57756 17.1277 9.87046C16.8348 10.1633 16.3599 10.1633 16.0671 9.87046L12.7512 6.55459V19.25C12.7512 19.6642 12.4154 20 12.0012 20C11.587 20 11.2512 19.6642 11.2512 19.25V6.55459L7.93533 9.87046C7.64244 10.1633 7.16756 10.1633 6.87467 9.87046C6.58178 9.57756 6.58178 9.10269 6.87467 8.8098L11.4709 4.2136Z"> </path></svg>
          </span>
        </button>
      </th>
      <th class="th">
        <button class="button">
          Likes Neil Diamond?
          <span class="sort"></span>
        </button>
      </th>
    </tr>
  </thead>
</table>

このUIを実現する方法に関するアイデアはありますか?これはおそらく、テーブルやボタンに関するものとはほとんど関係ありません。本当にThing Aを「しっかり」下/端をThing Bに揃える必要があります(幅は柔軟で、テキストを折り返すことができます)が、Thing Aは独自の行に折り返すことができません。

私はflexの値をいじってみましたが、どのような組み合わせでもテキストの折り返しが時期尚早になるか、まもなく遅くなります。

9
robertwbradford

視覚的な曖昧さ以外は何も問題はないと思います。ここに私の観察があります。

  • 実際のアイテムはしっかりと拘束されています。デフォルトでは、特に指定のない限り、要素は別の要素の後に続きます。
  • なぜ間隔があるのですか?これらには2つのバリエーションがあります
    • 最初:テキストが折り返し要素の内部にない場合(現在の状態)。このシナリオでは、幅だけでなくテキストも明示されていないため、テキストとスパンの両方に幅の自動割り当てがあり、テキストは、スパン要素が使用している1.25rem幅を除くすべての幅にしようとしています。また、w3cのドキュメントによると、テキストの位置揃えはまったく別の問題であるため、ルールは、指定された文字列のブレークポイントを識別するためにのみ存在し、スペースではありません。どのように行われるかを理解するには、 この問題 を参照してください。これは、大学で研究されている標準的な動的プログラミングの質問です。そのため、当然、位置合わせを行っている間はスペースが存在します。ブラウザが折りたたまない、利用可能な幅を覚えておいてください。
    • 2番目:テキストが折り返し要素内にある場合、span、p、divなどが考えられます。この場合も、幅の自動割り当ては幅は明示的に指定されていません。そして、この場合、要素がsortアイコンの1.25rem幅以外のすべてのスペースを占有しようとすることを実際にinspect要素で確認できます。

したがって、tight境界が存在します。動的な間隔が視覚的なあいまいさを引き起こしているだけです。

今解決策に来ています、JavaScriptの介入なしに思いつくことができる最も近い解決策は、完璧ではありませんが、

  • 要素、おそらくスパン内にテキストをラップします
  • Max-widthを指定して、このテキストの幅を制限します。

    button.button > span {
        max-width: 60%; // I saw this to be decent enough
        text-align: center; // This is to offset the visual effect of spacing
    }
    

注:text-align: centerは、これを使用しないという厳密な要件がない限り、不足しているスペースの影響を減らすためだけのものです。

これでご質問が解決したかどうかをお知らせください。

これは効果がどのようになるかです: enter image description here

これにはJSが必要だと思います。 5を除くすべての条件を満たす必要がある答えは次のとおりです。

const debounce = fn => {
  let frame;

  return (...params) => {
    if (frame) {
      cancelAnimationFrame(frame);
    }
    frame = requestAnimationFrame(() => {
      fn(...params);
    });
  };
};

const text = [...document.querySelectorAll(".text")];
const iconWidth = "1.25rem";

const positionIcon = () => {
  if (!text) return;
  
  text.forEach(t => {
    const width = t.getBoundingClientRect().width;

    const icon = t.nextElementSibling;
    if (!icon) return;
    
    icon.style.left = `calc(${width}px + ${iconWidth})`;
  });
};

positionIcon();
window.addEventListener("resize", debounce(positionIcon));
.table {
  border-collapse: collapse;
  width: 100%;
}

.thead {
  border-bottom: 3px solid #d0d3d3;
}

.thead .tr {
  vertical-align: bottom;
}

.button {
  padding: 1rem;
  text-align: start;
  font-family: Arial, "noto sans", sans-serif;
  font-size: 0.875rem;
  border: 0;
  background-color: transparent;
  width: 100%;
  font-weight: bold;
  line-height: 1.4;
  position: relative;
}

.sort {
  width: 1.25rem;
  height: 1.25rem;
  position: absolute;
  bottom: 1rem;
  left: 100%; /* no js fallback */
}

.sort svg {
  height: 1.25rem;
  width: 1.25rem;
}
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
   <svg id="arrow" viewBox="0 0 24 24" role="presentation"> <path d="M11.4709 4.2136C11.7638 3.92071 12.2386 3.92071 12.5315 4.2136L17.1277 8.8098C17.4206 9.10269 17.4206 9.57756 17.1277 9.87046C16.8348 10.1633 16.3599 10.1633 16.0671 9.87046L12.7512 6.55459V19.25C12.7512 19.6642 12.4154 20 12.0012 20C11.587 20 11.2512 19.6642 11.2512 19.25V6.55459L7.93533 9.87046C7.64244 10.1633 7.16756 10.1633 6.87467 9.87046C6.58178 9.57756 6.58178 9.10269 6.87467 8.8098L11.4709 4.2136Z"> </path></svg>
</svg>
<table class="table">
  <thead class="thead">
    <tr class="tr">
      <th class="th">
        <button class="button">
          <span class="text">Age</span>
          <span class="sort">
            <svg>
              <use xlink:href="#arrow">
            </svg>
          </span>
         </button>
      </th>
      <th class="th">
        <button class="button">
          <span class="text">Favourite Food</span>
          <span class="sort">
          <svg>
              <use xlink:href="#arrow">
            </svg>
          </span>
        </button>
      </th>
      <th class="th" aria-sort="ascending">
        <button class="button">
          <span class="text">Favorite Color</span>
          <span class="sort">
            <svg>
              <use xlink:href="#arrow">
            </svg>
          </span>
        </button>
      </th>
      <th class="th">
        <button class="button">
          <span class="text">Likes Neil Diamond?</span>
          <span class="sort">
            <svg>
              <use xlink:href="#arrow">
            </svg>
          </span>
        </button>
      </th>
    </tr>
  </thead>
</table>
1
sol

私はあなたがほとんど上手で、少しトリックである(3)を逃していると思います。アイコン要素の幅を0に等しくし、テキストと並べ替えアイコンの間の空白を無効にするというアイデアがあります。このために、テキスト用の追加のラッパーを使用し、フレックスボックスの使用を削除しました。

オーバーフローが発生しますが、パディングを適用しているため、問題にはなりません。必要に応じて、padding-rightを増やすこともできます

.table {
  border-collapse: collapse;
  width: 100%;
}

.thead {
  border-bottom: 3px solid #d0d3d3;
}

.thead .tr {
  vertical-align: bottom;
}

.button {
  padding: 1rem;
  text-align: start;
  font-family: Arial, "noto sans", sans-serif;
  font-size:0;
  border: 0;
  background-color: transparent;
  width: 100%;
  font-weight: bold;
  line-height: 1.4;
}
.button > span {
  font-size: 0.875rem;
}
.sort {
  width: 0;
  height: 1.25rem;
  display: inline-block;
  vertical-align: bottom;
}
<table class="table">
  <thead class="thead">
    <tr class="tr">
      <th class="th">
        <button class="button">
          <span>Age</span>
          <span class="sort"></span>
         </button>
      </th>
      <th class="th">
        <button class="button">
          <span>Favorite Food</span>
          <span class="sort"></span>
        </button>
      </th>
      <th class="th" aria-sort="ascending">
        <button class="button">
          <span>Favorite Color</span>
          <span class="sort">
            <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" role="presentation" style="width: 1.25rem; height: 1.25rem;"> <path d="M11.4709 4.2136C11.7638 3.92071 12.2386 3.92071 12.5315 4.2136L17.1277 8.8098C17.4206 9.10269 17.4206 9.57756 17.1277 9.87046C16.8348 10.1633 16.3599 10.1633 16.0671 9.87046L12.7512 6.55459V19.25C12.7512 19.6642 12.4154 20 12.0012 20C11.587 20 11.2512 19.6642 11.2512 19.25V6.55459L7.93533 9.87046C7.64244 10.1633 7.16756 10.1633 6.87467 9.87046C6.58178 9.57756 6.58178 9.10269 6.87467 8.8098L11.4709 4.2136Z"> </path></svg>
          </span>
        </button>
      </th>
      <th class="th">
        <button class="button">
          <span>Likes Neil Diamond?</span>
          <span class="sort"></span>
        </button>
      </th>
    </tr>
  </thead>
</table>
0
Temani Afif

あなたはこのように試すことができます:

<style>

.table {
  border-collapse: collapse;
  width: 100%;
}

.thead {
  border-bottom: 3px solid #d0d3d3;
}

.thead .tr {
  vertical-align: bottom;
}


.button {
  padding: 1rem;
  text-align: start;
  font-family: Arial, "noto sans", sans-serif;
  font-size: 0.875rem;
  border: 0;
  background-color: transparent;
    
 /* display: flex;
  align-items: flex-end;*/
  font-weight: bold;
  line-height: 1.4;
  float: left;
}
@media only screen and (min-width:502px)
{.button {
    width: calc(192px - 89px);
  }
  .button.food {
    width: calc(214px - 89px);
}
}

.sort {
  width: 1.25rem;
  height: 1.25rem;
  position: relative;
}
.sort svg {
  position: absolute;
}
</style>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <table class="table">
  <thead class="thead">
    <tr class="tr">
      <th class="th">
        <button class="button">
          Age
          <span class="sort"></span>
         </button>
      </th>
      <th class="th">
        <button class="button food">
          Favorite Food
          <span class="sort"></span>
        </button>
      </th>
      <th class="th" aria-sort="ascending">
        <button class="button">
          Favorite Color
          <span class="sort">
            <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" role="presentation" style="width: 1.25rem; height: 1.25rem;"> <path d="M11.4709 4.2136C11.7638 3.92071 12.2386 3.92071 12.5315 4.2136L17.1277 8.8098C17.4206 9.10269 17.4206 9.57756 17.1277 9.87046C16.8348 10.1633 16.3599 10.1633 16.0671 9.87046L12.7512 6.55459V19.25C12.7512 19.6642 12.4154 20 12.0012 20C11.587 20 11.2512 19.6642 11.2512 19.25V6.55459L7.93533 9.87046C7.64244 10.1633 7.16756 10.1633 6.87467 9.87046C6.58178 9.57756 6.58178 9.10269 6.87467 8.8098L11.4709 4.2136Z"> </path></svg>
          </span>
        </button>
      </th>
      <th class="th">
        <button class="button">
          Likes Neil Diamond?
          <span class="sort"></span>
        </button>
      </th>
    </tr>
  </thead>
</table>

この回答がお役に立てば幸いです。モバイルビュー用のCSSを作成していません。

0
Krishna Savani

シードのタイトルが動的でない場合は、簡単に修正できます。

このためには、最後のWord of Titleとsvgアイコンを一緒に配置する必要があります。

例:-html

<button>
 Long 

<span> title 
 <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" role="presentation" style="width: 1.25rem; height: 1.25rem;"> <path d="M11.4709 4.2136C11.7638 3.92071 12.2386 3.92071 12.5315 4.2136L17.1277 8.8098C17.4206 9.10269 17.4206 9.57756 17.1277 9.87046C16.8348 10.1633 16.3599 10.1633 16.0671 9.87046L12.7512 6.55459V19.25C12.7512 19.6642 12.4154 20 12.0012 20C11.587 20 11.2512 19.6642 11.2512 19.25V6.55459L7.93533 9.87046C7.64244 10.1633 7.16756 10.1633 6.87467 9.87046C6.58178 9.57756 6.58178 9.10269 6.87467 8.8098L11.4709 4.2136Z"> </path></svg>
</span>
</button>

.buttonクラスからdisplay:flexを削除し、追加されたスパンにスタイルdisplay:inline-blockを付与します

スパンがインラインブロックであるため、svgアイコンが別の行になることはありません。その前に少なくとも1つの単語があります

0