Usando CSS, cómo alinear "A" con firmeza "A" en la parte inferior / final de "B" donde "B" tiene un ancho y un ajuste de texto desconocidos

9

Tengo una tabla "ordenable" donde el encabezado de la columna actualmente ordenada muestra un icono:

ingrese la descripción de la imagen aquí

El icono de clasificación se mostrará al final del texto (es decir, admitimos LTR / RTL). Actualmente estoy usando display:flex. Sin embargo, si el ancho de la tabla se reduce y el texto del encabezado de la columna comienza a ajustarse, me encuentro con estados ambiguos donde no está claro qué columna está ordenada:

ingrese la descripción de la imagen aquí

En cambio, me gustaría cumplir con los siguientes requisitos:

  1. El ícono siempre debe estar "firmemente" alineado con el "final" de la línea de texto más larga (incluso si la celda / botón de ajuste es más ancho).
  2. El icono también debe estar alineado con la última fila de texto.
  3. El icono nunca debe ajustarse a una línea propia.
  4. El botón debe estar presente y debe abarcar todo el ancho de la celda. (Su estilo interno y el marcado pueden cambiar según sea necesario).
  5. CSS y HTML solo si es posible.
  6. No puede basarse en anchos de columna conocidos / establecidos o texto de encabezado.

Por ejemplo:

ingrese la descripción de la imagen aquí

He estado experimentando con un montón de diferentes combinaciones de display: inline/inline-block/flex/grid, position, ::before/::after, e incluso float(!) Pero no puedo conseguir el comportamiento deseado. Aquí está mi código actual que demuestra el 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>

¿Alguna idea sobre cómo lograr esta interfaz de usuario? Esto probablemente tiene poco que ver con la tabla o el botón. Realmente necesito Thing Aun fondo / extremo "apretado" alineado a Thing B(de un ancho flexible y que pueda tener texto ajustado) pero Thing Ano puedo ajustarlo a una línea propia.

He intentado jugar con los flexvalores, pero cualquier combinación hace que el texto se ajuste prematuramente o no lo suficientemente pronto.

robertwbradford
fuente
Traté de solucionar su problema con su actual CSS y HTML, sin embargo, el botón y el elemento span se combinaron cuando era un dolor de cabeza, así que decidí usar font-awesome con CSS y HTML. Aquí hay un ejemplo, espero que ayude
Stan Chacon
@stanchacon gracias por echar un vistazo. Debería haberlo mencionado, pero no tendré el lujo de establecer anchos de columna o saber cuál será el texto del encabezado antes de tiempo. Agregué # 6 a los requisitos.
robertwbradford
1
@stanchacon ... y podría ir por un chuletón ahora mismo :)
robertwbradford
@robertwbradford ¿Ya se ha abordado esto? ¿O todavía estás buscando una solución?
Furqan Rahamath
@MohammedFurqanRahamathM, esto aún no ha sido respondido. Todavía estás ...
robertwbradford

Respuestas:

1

Creo que necesitas JS para esto. Aquí hay una respuesta que debe cumplir con todas las condiciones excepto 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
fuente
1

Creo que no hay ningún problema aquí, excepto la ambigüedad visual. Aquí están mis observaciones.

  • Los artículos de hecho están estrechamente vinculados. Por defecto, cualquier elemento seguiría a otro a menos que se especifique lo contrario.
  • ¿Por qué hay un espacio? Hay dos variaciones de estos
    • Primero: si el texto no está dentro de ningún elemento de ajuste (el estado en el que se encuentra ahora). En este escenario, dado que no se menciona explícitamente el ancho, tanto para el texto como para el espacio, hay una asignación automática de ancho y el texto está tratando de abarcar todo el ancho, excepto el ancho de 1.25rem que está tomando el elemento span. Y de acuerdo con la documentación de w3c, las reglas existen solo para identificar los puntos de interrupción en una cadena dada y sin espacios, porque la justificación del texto es un problema completamente diferente. Consulte este problema para comprender cómo se hace, es una pregunta de programación dinámica estándar estudiada en la universidad. Así que, por supuesto, existirá espacio al hacer la justificación y recuerde el ancho disponible, que el navegador no colapsará.
    • Segundo: si el texto está dentro de un elemento de ajuste , podría ser span, p, div, etc. En este caso también, la asignación automática de ancho ocurre ya que no se especifica explícitamente ningún ancho. Y en este caso, puede ver en el elemento de inspección que el elemento intenta ocupar todo el espacio excepto el ancho de 1.25rem del icono de ordenación.

Existe un límite tan estrecho , es solo que el espaciado dinámico está causando la ambigüedad visual.

Ahora que llegamos a la solución, la solución más cercana que podría encontrar sin la intervención de JavaScript , aunque no es perfecta, es,

  • Envuelva el texto dentro de un elemento, tal vez un espacio
  • Limite el ancho de este texto dando un ancho máximo:

    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: El text-align: centerobjetivo es solo reducir el efecto de espacio perdido, a menos que tenga un requisito estricto de no ir con esto.

Avíseme si esto responde a su pregunta.

Así es como sería el efecto: ingrese la descripción de la imagen aquí

Furqan Rahamath
fuente
Gracias por la respuesta. Para esto tenemos un requisito para que sea al final.
robertwbradford
@robertwbradford He cambiado mi respuesta explicando el posible problema que enfrenta y propuso una solución. Avíseme si esto responde a su pregunta.
Furqan Rahamath
0

Creo que eres casi bueno y te falta el (3) que es un poco truco. Una idea es hacer que el elemento del icono tenga un ancho igual 0y desactivar cualquier espacio en blanco entre el texto y el icono de ordenación. Para esto utilizo un contenedor adicional para el texto y eliminé el uso de flexbox.

Tendrá un desbordamiento pero no es un problema ya que está aplicando relleno. También puedes aumentar el padding-rightsi quieres

.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
fuente
Gracias por la respuesta. Algunos puntos buenos, pero veo que no cumple con el "requisito 1", donde la flecha debería alinearse con el final de la fila de texto más larga. En el caso de "Color favorito", cuando "Color" se ajusta a la segunda línea, el icono debe alinearse horizontalmente con el final de "Favorito" como se muestra en la última captura de pantalla.
robertwbradford
1
@robertwbradford ah no lo entendí de esa manera ... pensé que debería ser estricto con el último. Creo que no tienes suerte para este requisito ...
Temani Afif
0

Si su título no es dinámico, entonces tengo una solución muy fácil.

para esto tendrás que poner la última palabra del título y el ícono de svg juntos

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

eliminar display: flex de la clase .button y dar display de estilo: bloque en línea al lapso agregado

debido a que span está bloqueado en línea, el ícono svg nunca estará en línea separada. al menos habrá una palabra delante de ella

Shirish Maharjan
fuente
Gracias por la respuesta. Estoy construyendo esto como un componente, por lo que el texto del título será dinámico :(
robertwbradford
Puede usar Js para poner la última palabra en span. No debería ser tan difícil
Shirish Maharjan
0

Podrías intentarlo así:

<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 respuesta te sea útil. ¡No hice CSS para la vista móvil!

Krishna Savani
fuente