En utilisant CSS, comment aligner «étroitement» «A» au bas / à la fin de «B» où «B» a une largeur et un habillage de texte inconnus

9

J'ai une table "triable" où l'en-tête de la colonne actuellement triée affiche une icône:

entrez la description de l'image ici

L'icône de tri doit être affichée à la fin du texte (c'est-à-dire que nous prenons en charge LTR / RTL). J'utilise actuellement display:flex. Cependant, si la largeur du tableau diminue et que le texte de l'en-tête de colonne commence à s'habiller, je tombe dans des états ambigus où il n'est pas clair quelle colonne est triée:

entrez la description de l'image ici

Au lieu de cela, je voudrais répondre aux exigences suivantes:

  1. L'icône doit toujours être "étroitement" alignée avec la "fin" de la plus longue ligne de texte (même si la cellule / le bouton d'habillage est plus large).
  2. L'icône doit également être alignée en bas de la dernière ligne de texte.
  3. L'icône ne doit jamais être placée sur une ligne à part.
  4. Le bouton doit être présent et doit s'étendre sur toute la largeur de la cellule. (Son style interne et le balisage peuvent changer selon les besoins.)
  5. CSS et HTML uniquement si possible.
  6. Il ne peut pas s'appuyer sur des largeurs de colonne ou un texte d'en-tête connus / définis.

Par exemple:

entrez la description de l'image ici

Je l' ai expérimenté avec un tas de différentes combinaisons de display: inline/inline-block/flex/grid, position, ::before/::afteret même float(!) Mais ne peut pas obtenir le comportement souhaité. Voici mon code actuel illustrant le problème:

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

Des idées sur la façon d'accomplir cette interface utilisateur? Cela n'a probablement pas grand chose à voir avec la table ou les boutons. Vraiment, j'ai besoin que le Thing Abas / l'extrémité soit "étroitement" aligné sur Thing B(d'une largeur flexible et qui peut avoir du texte enveloppé) mais je Thing Ane peux pas envelopper sur une ligne qui lui est propre.

J'ai essayé de jouer avec les flexvaleurs, mais toute combinaison permet de boucler le texte prématurément ou pas assez tôt.

robertwbradford
la source
J'ai essayé de résoudre votre problème avec vos css et html actuels, mais le bouton et l'élément span se sont combinés là où un mal de tête j'ai donc décidé d'utiliser font-awesome avec css et html ici est un exemple j'espère que cela aide
stan chacon
@stanchacon merci d'avoir regardé. J'aurais dû le mentionner, mais je n'aurai pas le luxe de définir des largeurs de colonne ou de savoir ce que le texte d'en-tête sera à l'avance. J'ai ajouté # 6 aux exigences.
robertwbradford
1
@stanchacon ... et je pourrais aller chercher un ribeye en ce moment :)
robertwbradford
@robertwbradford Est-ce déjà réglé? Ou vous cherchez toujours une solution?
Furqan Rahamath
@MohammedFurqanRahamathM, cela n'a pas encore été répondu. Toujours à la recherche ...
robertwbradford

Réponses:

1

Pensez que vous avez besoin de JS pour cela. Voici une réponse qui devrait répondre à toutes les conditions sauf 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
la source
1

Je pense qu'il n'y a aucun problème ici, sauf l'ambiguïté visuelle. Voici mes observations.

  • Les articles sont en fait étroitement liés. Par défaut, tout élément en suivrait un autre, sauf indication contraire.
  • Pourquoi il y a un espacement? Il en existe deux variantes
    • Premièrement: si le texte ne se trouve dans aucun élément d'habillage (l'état dans lequel il se trouve actuellement). Dans ce scénario, puisqu'il n'y a pas de largeur mentionnée explicitement, pour le texte comme pour la portée, il y a une affectation automatique de la largeur et le texte essaie de toute la largeur sauf la largeur de 1,25rem prise par l'élément span. Et selon la documentation du w3c, les règles n'existent que pour identifier les points d'arrêt sur une chaîne donnée et non l'espacement, car la justification du texte est un problème entièrement différent. Veuillez vous référer à ce problème pour comprendre comment cela se fait, c'est une question de programmation dynamique standard étudiée au collège. Bien sûr, l'espacement existera lors de la justification et n'oubliez pas la largeur disponible, que le navigateur ne va pas réduire.
    • Deuxièmement: si le texte se trouve à l'intérieur d'un élément d'habillage , il peut s'agir de span, p, div, etc. Dans ce cas également, l'affectation automatique de largeur se produit car aucune largeur n'est explicitement spécifiée. Et dans ce cas, vous pouvez réellement voir dans l'élément inspect que l'élément essaie d'occuper tout l'espace sauf la largeur de 1,25rem de l'icône de tri.

Il y a tellement de limites serrées , c'est juste que l'espacement dynamique est à l'origine de l'ambiguïté visuelle.

Venons-en maintenant à la solution, la solution la plus proche que j'ai pu trouver sans intervention de JavaScript , bien qu'elle ne soit pas parfaite, est,

  • Enveloppez le texte dans un élément, peut-être une étendue
  • Limitez la largeur de ce texte en donnant une largeur max:

    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
    }

Remarque: Le text-align: centern'est que pour réduire l'effet de l'espace manquant, sauf si vous avez l'obligation stricte de ne pas y aller.

Veuillez me faire savoir si cela répond à votre question.

C'est ainsi que l'effet serait: entrez la description de l'image ici

Furqan Rahamath
la source
Merci pour la réponse. Pour cela, nous avons besoin que ce soit à la fin.
robertwbradford
@robertwbradford J'ai changé ma réponse en expliquant le problème possible auquel vous êtes confronté et j'ai proposé une solution. Veuillez me faire savoir si cela répond à votre question.
Furqan Rahamath
0

Je pense que vous êtes presque bon et que vous manquez le (3) qui est un petit truc. Une idée est de rendre l'élément icône ayant une largeur égale à 0et de désactiver les espaces blancs entre le texte et l'icône de tri. Pour cela, j'utilise un wrapper supplémentaire pour le texte et j'ai supprimé l'utilisation de flexbox.

Vous aurez un débordement, mais ce n'est pas un problème puisque vous appliquez un remplissage. Vous pouvez également augmenter le padding-rightsi vous voulez

.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
la source
Merci pour la réponse. Quelques bons points, mais je vois qu'il ne répond pas à "l'exigence 1" où la flèche devrait être alignée avec l'extrémité de la plus longue ligne de texte. Dans le cas de "Couleur préférée", lorsque "Couleur" passe à la deuxième ligne, l'icône doit s'aligner horizontalement avec la fin de "Favori", comme indiqué dans la dernière capture d'écran.
robertwbradford
1
@robertwbradford ah ne l'a pas compris de cette façon .. Je pensais que ça devrait être serré avec le dernier. Je pense que vous n'avez pas de chance pour cette exigence ...
Temani Afif
0

si votre titre n'est pas dynamique, j'ai une solution très simple.

pour cela, vous devrez mettre ensemble le dernier mot du titre et l'icône svg dans span

par exemple: -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>

supprimer display: flex de la classe .button et donner un style display: inline-block à la plage ajoutée

en raison du fait que span est un bloc en ligne, l'icône svg ne sera jamais en ligne séparée. il y aura au moins un mot devant

Shirish Maharjan
la source
Merci pour la réponse. Je construis ceci en tant que composant, donc le texte du titre sera dynamique :(
robertwbradford
Vous pouvez utiliser Js pour mettre le dernier mot dans l'intervalle. Ça ne devrait pas être si difficile
Shirish Maharjan
0

Vous pouvez essayer comme ceci:

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

J'espère que cette réponse vous sera utile.Je n'ai pas fait de CSS pour la vue mobile!

Krishna Savani
la source