Usando CSS, como "alinhar" firmemente "A" à parte inferior / final de "B", onde "B" tem largura e quebra de texto desconhecidas

9

Eu tenho uma tabela "classificável" onde o cabeçalho da coluna atualmente classificada exibe um ícone:

insira a descrição da imagem aqui

O ícone de classificação deve ser exibido no final do texto (ou seja, apoiamos LTR / RTL). Atualmente estou usando display:flex. No entanto, se a largura da tabela diminuir e o texto do cabeçalho da coluna começar a quebrar, eu corro para estados ambíguos em que não está claro qual coluna está classificada:

insira a descrição da imagem aqui

Em vez disso, gostaria de atender aos seguintes requisitos:

  1. O ícone sempre deve estar "firmemente" alinhado com o "final" da linha de texto mais longa (mesmo que a célula / botão de agrupamento seja mais amplo).
  2. O ícone também deve estar alinhado com a última linha do texto.
  3. O ícone nunca deve quebrar em uma linha própria.
  4. O botão deve estar presente e deve abranger toda a largura da célula. (O estilo interno e a marcação podem mudar conforme necessário.)
  5. CSS e HTML somente se possível.
  6. Ele não pode confiar nas larguras conhecidas / definidas da coluna ou no texto do cabeçalho.

Por exemplo:

insira a descrição da imagem aqui

Estive a experimentar com um monte de diferentes combinações de display: inline/inline-block/flex/grid, position, ::before/::after, e até mesmo float(!), Mas não pode obter o comportamento desejado. Aqui está o meu código atual demonstrando o problema:

.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>

Alguma idéia de como realizar essa interface do usuário? Provavelmente isso tem pouco a ver com as coisas da mesa ou do botão. Realmente preciso Thing Aalinhar a parte inferior / extremidade "firmemente" Thing B(de uma largura flexível e que possa ter texto Thing Aem quebra automática ), mas não possa quebrar em uma linha própria.

Eu tentei mexer com os flexvalores, mas qualquer combinação faz com que o texto seja quebrado prematuramente ou não em breve.

robertwbradford
fonte
Eu tentei corrigir o problema com o seu css atual e html no entanto, o botão eo elemento span combinada, se uma dor de cabeça, então eu decidi usar font-impressionante com CSS e HTML aqui está um exemplo Espero que ajude
stan chacon
@stanchacon obrigado por dar uma olhada. Eu deveria ter mencionado, mas não terei o luxo de definir as larguras das colunas ou saber qual será o texto do cabeçalho antes do tempo. Eu adicionei o número 6 aos requisitos.
robertwbradford
11
@stanchacon ... e eu poderia ir para um bife sobre a direita agora :)
robertwbradford
@robertwbradford Isso já foi abordado? Ou você ainda está procurando uma solução?
Furqan Rahamath 11/12/19
@MohammedFurqanRahamathM, isso ainda não foi respondido. Ainda olhando ...
robertwbradford

Respostas:

1

Pense que você precisa de JS para isso. Aqui está uma resposta que deve atender a todas as condições, exceto 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>

Sol
fonte
1

Eu acho que não há nenhum problema aqui, exceto a ambiguidade visual. Aqui estão minhas observações.

  • Os itens de fato estão bem vinculados. Por padrão, qualquer elemento seguiria outro, a menos que especificado de outra forma.
  • Por que existe um espaçamento? Existem duas variações desses
    • Primeiro: se o texto não estiver dentro de nenhum elemento de quebra automática (o estado em que está agora). Nesse cenário, como não há largura mencionada explicitamente, tanto para o texto quanto para a amplitude, há atribuição automática de largura e o texto está tentando toda a largura, exceto a largura de 1,25rem que o elemento de ampliação está usando. E de acordo com a documentação do w3c, as regras existem apenas para identificar os pontos de interrupção em uma determinada string e não o espaçamento, porque a justificação de texto é um problema totalmente diferente. Consulte este problema para entender como é feito. É uma questão de programação dinâmica padrão estudada na faculdade. Portanto, é claro que o espaçamento existirá ao justificar e lembre-se da largura disponível, que o navegador não entrará em colapso.
    • Segundo: se o texto estiver dentro de um elemento de quebra automática, pode ser span, p, div etc. Nesse caso também, a atribuição automática de largura acontece porque nenhuma largura é especificada explicitamente. E, nesse caso, você pode realmente ver no elemento inspecionar que o elemento tenta ocupar todo o espaço, exceto a largura de 1,25rem do ícone de classificação.

Existe um limite tão estreito que apenas o espaçamento dinâmico está causando a ambiguidade visual.

Agora, chegando à solução, a solução mais próxima que eu poderia encontrar sem a intervenção do JavaScript , embora não seja perfeita, é:

  • Coloque o texto dentro de um elemento, talvez um espaço
  • Limite a largura deste texto, fornecendo uma largura máxima:

    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
    }

Nota: O text-align: centerobjetivo é apenas reduzir o efeito de falta de espaço, a menos que você tenha um requisito estrito de não concordar com isso.

Informe-me se isso resolver sua pergunta.

É assim que o efeito seria: insira a descrição da imagem aqui

Furqan Rahamath
fonte
Obrigado pela resposta. Para isso, temos um requisito para que esteja no final.
Robertwbradford
@robertwbradford Alterei minha resposta para explicar o possível problema que você está enfrentando e propôs uma solução. Informe-me se isso responder à sua pergunta.
Furqan Rahamath
0

Eu acho que você é quase bom e sente falta do (3), o que é um truque. Uma idéia é fazer com que o elemento icon tenha uma largura igual a0 e desativar qualquer espaço em branco entre o texto e o ícone de classificação. Para isso, uso um invólucro extra para o texto e removi o uso do flexbox.

Você terá algum excesso, mas isso não é um problema, pois você está aplicando o preenchimento. Você também pode aumentar opadding-right se quiser

.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>

Temani Afif
fonte
Obrigado pela resposta. Alguns bons pontos, mas estou vendo que ele não atende ao "requisito 1", onde a seta precisa estar alinhada com o final da linha mais longa do texto. No caso de "Cor favorita", quando "Cor" passa para a segunda linha, o ícone deve alinhar horizontalmente com o final de "Favorito", conforme mostrado na última captura de tela.
Robertwbradford 6/12/19
11
@robertwbradford ah não entendi dessa maneira .. Eu pensei que deveria ser apertado com o último. Eu acho que você está fora de sorte para este requisito ...
temanitas Afif
0

Se o título do seu cabeçalho não for dinâmico, eu tenho uma correção muito fácil.

para isso, você terá que colocar a última palavra do título e o ícone svg juntos

por exemplo: -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>

remove display: flex da classe .button e dê estilo display: inline-block ao intervalo adicionado

devido ao span ser inline-block, o ícone svg nunca estará em uma linha separada. haverá pelo menos uma palavra na frente

Shirish Maharjan
fonte
Obrigado pela resposta. Estou construindo isso como um componente, de modo que o texto do título será dinâmico :(
robertwbradford
Você pode usar Js para colocar a última palavra no intervalo. Deve não é difícil
Shirish Maharjan
0

Você pode tentar assim:

<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>

Espero que esta resposta seja útil para você.Não fiz css para visualização em dispositivos móveis!

Krishna Savani
fonte