Используя CSS, как «плотно» выровнять «A» по низу / концу «B», где «B» имеет неизвестную ширину и перенос текста


9

У меня есть «сортируемая» таблица, где в заголовке сортируемого в данный момент столбца отображается значок:

введите описание изображения здесь

Значок сортировки должен отображаться в конце текста (т. Е. Мы поддерживаем LTR / RTL). Я сейчас пользуюсь display:flex. Однако, если ширина таблицы уменьшается и текст заголовка столбца начинает переноситься, я сталкиваюсь с неоднозначными состояниями, когда неясно, какой столбец отсортирован:

введите описание изображения здесь

Вместо этого я хотел бы соответствовать следующим требованиям:

  1. Значок всегда должен быть «тесно» выровнен с «концом» самой длинной строки текста (даже если ячейка / кнопка переноса шире).
  2. Значок также должен быть выровнен снизу относительно последней строки текста.
  3. Значок никогда не должен переноситься на собственную линию.
  4. Кнопка должна присутствовать и должна охватывать всю ширину ячейки. (Это внутренняя стилизация и разметка может меняться по мере необходимости.)
  5. CSS и HTML, только если это вообще возможно.
  6. Он не может полагаться на известную / установленную ширину столбца или текст заголовка.

Например:

введите описание изображения здесь

Я экспериментировал с кучей различных комбинаций display: inline/inline-block/flex/grid, position, ::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>

Любые идеи о том, как сделать этот интерфейс? Это, вероятно, имеет мало общего с таблицей или кнопками. На самом деле мне нужно Thing A«плотно» нижний / конец выровнен по Thing B(гибкой ширины и который может иметь обернутый текст), но Thing Aне могу перенести на собственную линию.

Я пробовал возиться со flexзначениями, но любая комбинация либо делает перенос текста преждевременным, либо недостаточно быстрым.


Я попытался исправить вашу проблему с вашими текущими css и html, однако кнопка и элемент span объединились, где возникла головная боль, поэтому я решил использовать font-awesome с css и html, вот пример, надеюсь, это поможет
stan

@stanchacon спасибо, что заглянули. Я должен был упомянуть, но у меня не будет роскоши устанавливать ширину столбцов или знать, какой текст заголовка будет раньше времени. Я добавил № 6 к требованиям.
Робертбрадфорд

1
@stanchacon ... и я могу пойти на рибай прямо сейчас :)
robertwbradford

@robertwbradford Это уже решено? Или вы все еще ищете решение?
Фуркан Рахамат

@MohammedFurqanRahamathM, это еще не ответили. Все еще смотрю ...
Робертбрадфорд

Ответы:


1

Думаю, вам нужен 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

Я думаю, что здесь нет никаких проблем, кроме визуальной неоднозначности. Вот мои наблюдения.

  • Предметы на самом деле тесно связаны. По умолчанию любой элемент будет следовать за другим, если не указано иное.
  • Почему есть интервал? Есть два варианта этих
    • Первое: если текст не находится внутри какого-либо элемента обтекания (состояние, в котором он находится сейчас). В этом сценарии, поскольку здесь не указана явно ширина, как для текста, так и для span, существует автоматическое присвоение ширины, и текст пытается использовать всю ширину, кроме ширины 1.25rem, которую занимает элемент span. И в соответствии с документацией w3c, правила существуют только для определения точек останова в данной строке, а не через пробелы, потому что выравнивание текста - это совсем другая проблема. Пожалуйста, обратитесь к этой проблеме, чтобы понять, как это делается, это стандартный вопрос динамического программирования, изучаемый в колледже. Поэтому, разумеется, интервал будет существовать при выполнении выравнивания, и, пожалуйста, помните о доступной ширине, которую браузер не собирается свернуть.
    • Второе: если текст находится внутри обертывающего элемента , это могут быть span, p, div и т. Д. В этом случае также происходит автоматическое назначение ширины, поскольку ширина явно не указана. И в этом случае вы можете увидеть в элементе inspect, что этот элемент пытается занять все пространство, кроме ширины иконки сортировки в 1,25 об.

Такая тесная связь существует, просто динамический интервал вызывает визуальную неоднозначность.

Теперь, перейдя к решению, самое близкое решение, которое я мог бы предложить без вмешательства JavaScript , хотя и не идеально, это

  • Обернуть текст внутри элемента, возможно, span
  • Ограничьте ширину этого текста, указав максимальную ширину:

    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 только уменьшить влияние недостающего пространства, если вы не имеете строгое требование не идти с этим.

Пожалуйста, дайте мне знать, если это отвечает на ваш вопрос.

Вот как будет выглядеть эффект: введите описание изображения здесь


Спасибо за ответ. Для этого у нас есть требование, чтобы оно было в конце.
Робертбрадфорд

@robertwbradford Я изменил свой ответ, объяснив возможную проблему, с которой вы столкнулись, и предложил решение. Пожалуйста, дайте мне знать, если это ответит на ваш вопрос.
Фуркан Рахамат

0

Я думаю, что вы почти хороши и упускаете (3), что немного хитрость. Идея состоит в том, чтобы сделать элемент значка шириной равным 0и отключить все пробелы между текстом и значком сортировки. Для этого я использую дополнительную обертку для текста и убрал использование flexbox.

У вас будет некоторое переполнение, но это не проблема, так как вы применяете отступы. Вы также можете увеличить, 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>


Спасибо за ответ. Некоторые хорошие моменты, но я вижу, что это не соответствует «требованию 1», где стрелку нужно было бы выровнять с концом самого длинного ряда текста. В случае «Favorite Color», когда «Color» переносится на вторую строку, значок должен выровняться по горизонтали с концом «Favorite», как показано на последнем скриншоте.
Робертбрадфорд

1
@robertwbradford ах не понимал этого таким образом .. Я думал, что это должно быть тесно с последним. Я думаю, что вам не повезло с этим требованием ...
Темани Афиф

0

если ваш заголовок не динамический, то я могу легко это исправить.

для этого вам придется сложить последнее слово заголовка и значок SVG в span

например: -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>

удалить display: flex из класса .button и присвоить стилю display: inline-block добавленный диапазон

из-за того, что span является встроенным блоком, значок svg никогда не будет в отдельной строке. перед ним будет хотя бы одно слово


Спасибо за ответ. Я
строю

Вы можете использовать Js, чтобы поместить последнее слово в span. Это не должно быть так сложно
Шириш Махарджан

0

Вы можете попробовать вот так:

<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 для мобильного просмотра!

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.