Tablas de rejilla CSS flexibles


Ver una lista de clientes potenciales (contactos fríos)

Como ya hemos comenzado, finalmente puedo hablar sobre un proyecto secreto en el que he estado trabajando durante los últimos dos años. Una de las características interesantes de Teamwork CRM es una vista de lista.

Este es un componente poderoso que ocurre siete veces en la aplicación. De hecho, una mesa sobre esteroides. Podría decir mucho, pero no quiero aburrirte. Me centraré en cómo implementamos esta flexibilidad con solo unas pocas líneas de CSS (Grid). A saber, cómo diseñamos tablas de datos pesados, cómo admitimos el cambio de tamaño de columnas y mucho más.

Primero, se debe explicar el contexto, comenzando con el propósito y las tareas de diseño de estas tablas. Si esto no le interesa, no dude en proceder inmediatamente a la implementación técnica .

En primer lugar, nuestra solución permite a los clientes ver rápidamente listas, por ejemplo, clientes potenciales o contactos, y notar detalles importantes. No se parece a una hoja de cálculo de Excel: es mejor que nos ocupemos del diseño de datos si hay muchos.

Absolutamente todo funciona en un diseño flexible adaptable. Comenzamos con la opción más estrecha y personalizamos el diseño según el contenido, el diseño y los casos de uso (no tenemos puntos de interrupción orientados al dispositivo).

En el ancho mínimo de la pantalla, las columnas se apilan verticalmente, ocupando todo el ancho de la pantalla.


Cómo se ve la lista en una pantalla estrecha

Las mesas flexibles no son fáciles de hacer. Puede elegir entre varias plantillas existentes . Piense en la información que buscan los usuarios y elija sabiamente.

Una vez que tenemos suficientes píxeles en la pantalla, cambiamos a un diseño más típico, para que las columnas ... bueno, se conviertan en columnas. Entonces no hay cambios importantes en el diseño, pero aún queremos mostrar las columnas lo más conveniente posible para el cliente.

Supongamos que tenemos muchas columnas (más adelante veremos cómo el usuario puede personalizarlas). Primero, la tabla debe al menos llenar el ancho de la pantalla. En segundo lugar, el ancho de las columnas debe determinarse por su contenido y el tipo de valores. Por ejemplo, texto corto / largo, fecha, número, URL, etc. Las columnas con una fecha deben ocupar menos espacio que las columnas de texto largo.

Las columnas deben tener un ancho mínimo. El resultado es a menudo una tabla que se desplaza tanto vertical como horizontalmente.


Cómo el diseño depende del ancho de la ventana. Perdón por el temblor del GIF, te daré algunos ejemplos interactivos más adelante.

Para comenzar, al máximo usamos el CSS regular de la vieja escuela para la tabla. Luego lo mejoramos con CSS Grid. Luego, mostraré cómo los usuarios pueden cambiar el tamaño de las columnas con las herramientas de cuadrícula, lo cual era mucho más incómodo con el CSS normal.

Bueno, ya muestra CSS Grid


No soy un experto en CSS Grid, pero me gusta. Esta es una herramienta extremadamente poderosa y simple que implementa diseños complejos con un código mínimo. Aquí omitiré la introducción a la tecnología. Puede leer The New CSS Layouts de Rachel Andrew o The Complete Grid Guide . Cuando termines de pensar dónde ha estado esta herramienta toda tu vida, regresa a mí.

Primero, aplique display:grid a <table> para convertir la tabla en una grilla. Esto no romperá nada: si el navegador no es compatible con Grid, utilizará display:table . Los elementos secundarios <thead> y <tbody> convierten en elementos de malla. No necesitamos pensar en <thead> , <tbody> o incluso <tr> . Queremos diseñar nuestro <th> y <td> en esta cuadrícula aplicando display:grid a cada uno de ellos (es decir, cuadrículas dentro de las cuadrículas), pero esto no es lo ideal. Cada cuadrícula <tr> será independiente de las demás, y esto no es bueno (verá más adelante que el mismo problema con Flexbox).

La solución alternativa es usar display:contents en <thead> , <tbody> y <tr> . Básicamente, esto los elimina del diseño de cuadrícula, empujando hacia adelante los elementos secundarios ( <th> y <td> ).

Luego usamos la regla mágica grid-template-columns para controlar los elementos de la cuadrícula. Sí, solo una línea de CSS. Por ejemplo, si tenemos una columna de fecha y una columna de URL, se verá así:

 grid-template-columns: minmax(150px, 1.33fr) minmax(150px, 2.33fr); 

Usamos el mismo tamaño mínimo para todas las columnas, pero el valor máximo ( fr ) está determinado por el tipo de datos de la columna. Intenté max-content auto y max-content , pero se nos ocurrió una mejor opción. Aquí hay un ejemplo simplificado: una tabla interactiva con código . Intenta cambiar el tamaño de la ventana.

Cambiar anchos de columna con cuadrícula


Además, en nuestras tablas puede intercambiar, cambiar el ancho y ocultar las columnas. Esto último es importante porque se admiten muchas columnas con diferentes tipos de datos: estas son las propiedades del elemento en sí (por ejemplo, clientes potenciales), las propiedades de elementos relacionados (por ejemplo, una empresa asociada a un cliente potencial) y campos personalizados.

Por ejemplo, un usuario puede crear un campo personalizado (fecha) para los contactos llamado "Fecha de nacimiento", que se rastreará en el sistema para cada contacto.

Como al crear un campo personalizado, se selecciona el tipo "Fecha", el sistema procesará este campo teniendo en cuenta este tipo. Primero, explicaré cómo cambia el ancho.

  1. Cuando el usuario mueve el cursor sobre el encabezado de la columna, se muestra un marcador de cambio de tamaño a la derecha. Escuchamos el evento mousedown en el control deslizante de cambio de tamaño.
  2. Cuando el usuario hace clic en el control deslizante, mousemove algunos métodos más para escuchar los eventos mousemove y mousedown (en la window ). En esta etapa, también agregamos algunas clases de decoración.
  3. Cuando el usuario mueve el mouse, calculamos el ancho de la nueva columna teniendo en cuenta la posición del cursor, la posición de desplazamiento de la tabla y el mínimo establecido. Luego, restablecemos la regla de grid-template-columns para <table> (a través del atributo de style ), esta vez reemplazando el valor máximo ( fr ) con un píxel. Por ejemplo, grid-template-columns: minmax(150px, 1.33fr) 296px; . Esto se realiza mediante requestAnimationFrame para proporcionar la animación más fluida posible.
  4. Cuando llega el mouseup , cancelamos los oyentes de eventos y eliminamos las clases.

Prueba este ejemplo simplificado .

Sorprendentemente, es suficiente actualizar solo un elemento en el DOM, y no todas las celdas.

Siempre desarrollamos una interfaz de usuario basada en la entrada táctil, pero en este caso es bastante normal no admitirla. Esta es una acción demasiado precisa. Incluso si quisiera cambiar el tamaño de la columna en la pantalla táctil, probablemente esperaría otra interacción, por ejemplo, a través de un gesto multitáctil.

Columnas de ancho fijo


Es posible que haya notado que estaba en silencio sobre algo. De hecho, el ancho de no solo una columna, sino de todas las columnas cambia. Tal vez ni siquiera notaste esto, porque así es como debería funcionar.

Inicialmente, pensé que a los usuarios les gustaría: cuando estiran o aprietan columnas, otros también se ajustan. Si las columnas llenan bien el ancho de la pantalla, y usted estrecha una de ellas, entonces las otras pueden expandirse si hay contenido que no cabe en una línea. Prueba este ejemplo .

Pero después de una pequeña prueba de usuario, resultó que para las personas este es un comportamiento inesperado. El usuario siente una cierta pérdida de control cuando sus acciones causan efectos secundarios impredecibles.

No debemos hacer suposiciones basadas en qué columnas interactuaron y cuáles no. Al cambiar el tamaño de una columna, el usuario ya podría tomar una decisión implícita de que el ancho del resto es perfecto.

Por lo tanto, si abre la aplicación por primera vez, las columnas se presentan de manera óptima. Si cambia el tamaño de la pantalla, las columnas también cambiarán de acuerdo con el mismo principio. Tan pronto como toque el control deslizante para cambiar el tamaño de cualquier columna, se fijará el ancho de todas las columnas visibles.


Antes, durante y después de cambiar el ancho de la columna. Nuevamente, lamento que el GIF se mueva un poco

Cada vez que se cambia o cambia el tamaño de una columna, creamos un registro localStorage independiente que coincide con el identificador de columna con un valor de píxel para preservar las preferencias del usuario.

No recuerdo exactamente por qué decidimos establecer un valor fijo en píxeles, no una opción de adaptación. Quizás por simplicidad. O porque, en ausencia de soporte para Grid y display:contents hay un retroceso hacia un enfoque más arcaico para ajustar el ancho de las columnas.

Probablemente, la opción adaptativa en cualquier caso no corresponderá a las intenciones del usuario. No podemos suponer que lo más importante para él es hacer que todas las columnas sean más pequeñas para que todas permanezcan en la pantalla. Si una persona ha cambiado el ancho de la columna, quiere ver una cierta cantidad de contenido en esta columna. Si tenemos un bloqueo adaptativo, y luego se estrecha en una ventana más pequeña, ignoramos la elección de la persona. Tendrá que cambiar el ancho de la columna nuevamente para ver el mismo contenido. Es poco probable que el usuario piense: "Hmm, quiero que esta columna ocupe el 20% de la ventana, incluso si la cambio". Sin embargo, profundizo demasiado en la situación límite: de hecho, los usuarios rara vez cambian el tamaño de las ventanas.

Mover y eliminar columnas



Interfaz para personalizar columnas mostradas

Imagine que un usuario ha cambiado un conjunto de columnas a través de esta interfaz. Si ninguna de las columnas seleccionadas ha sido modificada previamente, se mostrarán utilizando los valores predeterminados grid-template-column , según el tipo de datos. Por ejemplo, minmax(150px, 3.33fr) .

Si el ancho de una columna se fija en localStorage, arreglamos el ancho de todas las columnas seleccionadas y también almacenamos estos valores en localStorage.

Con el tiempo, cada vez más columnas mantienen un ancho fijo. Para los usuarios, la única forma de volver al diseño receptivo es restablecer las columnas.

También almacenamos una matriz de identificadores de columna en localStorage, separados de las entradas de ancho.

"¿Por qué no usaste {{libraryName}}?"


Con la biblioteca de JavaScript, la solución será pesada, nerviosa, no proporcionará interactividad e incluso puede no admitir <table> en absoluto. Tampoco quería escribir algo así. Pensé: "Debe haber una mejor manera".

"¿Por qué no usaste Flexbox?"


Cada línea será evaluada / mostrada independientemente una de la otra. Es posible que la columna no esté alineada con la columna anterior debido al diferente volumen de contenido.

Podría cambiar a <div> para columnas con celdas agrupadas verticalmente dentro. Pero no quería hacer esto. Quería usar <table>. Además, podríamos encontrar fácilmente otros problemas: por ejemplo, falta de coincidencia de celdas en altura entre columnas.

"¿Por qué no <colgroup> ?"


De hecho, <colgroup> es un elemento antiguo conveniente. Después de definir columnas usando <col>, los estilos aplicados a uno se aplicarán efectivamente a todas las celdas de esa columna.

Pero esto resultó ser una solución demasiado limitada. Lo intentamos, pero muy rápidamente lo rechazamos. Tan rápido que no puedo recordar exactamente cuáles fueron los problemas. Estoy casi seguro de que fue imposible lograr el nivel deseado de adaptabilidad y que no funcionó con Flexbox y Grid.

"¿Por qué no usaste el diseño de tabla: arreglado?"


Podría aplicar el table-layout: fixed regla table-layout: fixed en <table> y establecer el ancho de columna como un porcentaje. Pero mirando los ejemplos y jugando con esta regla, tuve la impresión de que solo funciona en mesas con un ancho del 100%. Además, cambiar el tamaño de una columna cambia el tamaño de las otras columnas para alcanzar un ancho total del 100%.

"¡Pero podrías sobrevivir con tablas simples!"


Sí, las tablas listas para usar son capaces de muchas cosas inteligentes, pero no pueden soportar de manera efectiva todo lo que quería implementar. No estoy de acuerdo Muy bien mago, enséñame.

No vaya demasiado lejos con la pantalla: contenido


La display: contents valor de display: contents permitido para guardar el diseño de la tabla. Úselo solo cuando realmente lo necesite. Algunos navegadores tienen, o al menos han tenido problemas de accesibilidad y lectores de pantalla.

Encontramos una display: contents extraña display: contents error de display: contents con arrastrar y soltar nativos en Firefox.

Afortunadamente, pronto se lanzará una función de subcuadrícula que permitirá que los elementos secundarios se integren correctamente en las cuadrículas. En nuestra aplicación, solo queremos simplificar el marcado, pero las subredes abrirán las puertas a orgías de cuadrículas multidimensionales salvajes. Consulte "Por qué mostrar: el contenido no es un diseño de cuadrícula CSS" .

Supongo que olvidé algo


Parece que todavía hubo un problema con el desbordamiento del texto al cambiar el tamaño de las columnas, pero no recuerdo exactamente.

Para guardar los encabezados de la tabla al desplazarse hacia abajo, usamos position: sticky . Esta es una gran mejora y se degrada muy bien en navegadores antiguos. Sin embargo, para los usuarios de IE11 tenemos JavaScript de respaldo. De hecho, no recomendaría la position: sticky debido a dificultades con el desplazamiento horizontal.

Ni siquiera mencioné algunas de las funciones de nuestras vistas de lista. Por ejemplo, los usuarios pueden aplicar, guardar e intercambiar filtros personalizados (por ejemplo, mostrar clientes potenciales por encima de $ 500 con clientes potenciales en Europa). En estos filtros, puede memorizar un conjunto de columnas para mostrar siempre columnas específicas para un flujo de trabajo en particular.

Pronto implementaremos la edición masiva en la vista de lista, así como también exportaremos vistas personalizadas a CSV.

De todos modos, gracias por leer.

Source: https://habr.com/ru/post/452922/


All Articles