Normalmente, la conexión entre CSS y HTML es que los selectores de CSS coinciden con los elementos HTML y el CSS les aplica estilo. CSS no conoce el contenido real del HTML. Pero hay una forma en que CSS puede obtener datos en HTML, siempre que esos datos estén dentro de un atributo en ese elemento HTML.
Es como esto:
div::after {
content: attr(data-whatever);
}
Eso es ciertamente interesante. Puede usarlo para información sobre herramientas (bastante inaccesible), por ejemplo:
<button data-tooltip="Information only mouse-having sighted people will see.">
Button
</button>
button:hover::after {
content: attr(data-tooltip);
/* positioned and styled and whatnot */
/* ya, a :focus style would buy you a tad more a11y */
}
Pero no puede poner HTML en el valor del atributo, por lo que la información sobre herramientas se limita a un valor de cadena y no puede tener un título, enlace o algo por el estilo dentro de ellos.
Aquí hay un caso de uso mejor. Hay una hoja de estilo de impresión antigua de color castaño donde se utiliza attr()
para agregar las URL a los enlaces, de modo que pueda ver realmente a qué se enlaza un enlace:
@media (print) {
a[href]::after {
content: " (" attr(href) " )";
}
}
Eso es inteligente. Pero que mas ¿Podrías pasar un color?
<h2 data-color="#f06d06">
Custom Colored Header
</h2>
Eso no es inválido, pero no es útil.
h2 {
/* Not gonna work */
color: attr(data-color);
}
El valor de attr()
es un cuerda. Aunque esa cadena tiene el mismo formato que un código hexadecimal, no se utilizará como código hexadecimal.
Tampoco puede pasar una URL que realmente se pueda usar en algo como background-image()
. Tampoco puedes pasar una unidad como 3
, 20px
o 4rem
o 0.8vw
.
La función attr () de CSS es solo cadenas, y las cadenas solo son realmente útiles como content
, y content
(siendo no seleccionable y algo inaccesible) no es particularmente útil de todos modos. No puede seleccionar el texto del contenido de psuedo, por ejemplo, ni buscarlo, lo que lo hace bastante inaccesible.
¿Sabes qué puede pasar cualquier tipo de valor y es igualmente fácil de implementar como atributos?
Propiedades personalizadas de CSS!
Puede colocarlos directamente en el style
atributo de cualquier elemento. Ahora esos valores están disponibles para ese elemento:
<button
style="
--tooltip-string: 'Ug. Tooltips.';
--tooltip-color: #f06d06;
--tooltip-font-size: 11px;
--tooltip-top: -10px
"
>
Button
</button>
Pasamos una cadena a CSS arriba, pero también valores de color y longitud. Esos valores se pueden usar inmediatamente tal como están:
button::after {
content: var(--tooltip-string);
color: var(--tooltip-color);
font-size: var(--tooltip-font-size);
}
Aquí está esa demostración con algo de “lógica” complicada (tendría que mejorarse mucho para que sea realmente útil) para permitir variaciones:
Vea las propiedades personalizadas de Pen CSS Mo ‘Betta’ que attr () por Chris Coyier (@chriscoyier) en CodePen.
Esto realmente no es más accesible, para que conste. Si estuviera implementando información sobre herramientas de verdad, probablemente leería todo esto.
¿Qué pasa con otros casos de uso “buenos” para attr ()?
Uno que surge mucho son las tablas de datos receptivas. Imagine una tabla con encabezados a lo largo de una fila superior y filas de datos a continuación:
<table>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
....
</tr>
</thead>
<tbody>
<tr>
<td>Chris</td>
<td>Coyier</td>
...
</tr>
...
</tbody>
</table>
Filas de datos como esa pueden volverse problemáticas en pantallas pequeñas (demasiado anchas). Entonces, en una tabla de datos de respuesta, podríamos ocultar esa fila superior y mostrar etiquetas por celda en su lugar.
@media (max-width: 500px) {
thead {
display: none;
}
/* Need to reveal another label now that we've hidden the normal labels */
}
¿De dónde viene esa etiqueta? Podríamos hacer…
. ...
<tr>
<td data-label="First Name">Chris</td>
<td data-label="Last Name">Coyier</td>
...
</tr>
Entonces:
td::before {
content: attr(data-label);
/* Also display: block things and such */
}
Ese es un caso de uso bastante bueno. Si usamos algún método de ocultación accesible para eso <thead>
, incluso podría aprobarse por todos los medios.
Pero esto mismo es posible con las propiedades personalizadas de CSS …
. ...
<tr>
<td style="--label: 'First Name';">Chris</td>
<td style="--label: 'Last Name';">Chris</td>
...
</tr>
td::before {
content: var(--label);
...
}
Eric Bidelman me señaló un método para usar el contenido psueudo para mostrar el valor de una entrada.
<style>
input {
vertical-align: middle;
margin: 2em;
font-size: 14px;
height: 20px;
}
input::after {
content: attr(data-value) "https://css-tricks.com/" attr(max);
position: relative;
left: 135px;
top: -20px;
}
</style>
<input type="range" min="0" max="100" value="25">
<script>
var input = document.querySelector('input');
input.dataset.value = input.value; // Set an initial value.
input.addEventListener('change', function(e) {
this.dataset.value = this.value;
});
</script>
Eso se siente un poco peligroso para mí, ya que no pensé que se suponía que el pseudo contenido funcionara en elementos reemplazados como un <input>
. Probablemente sea un trabajo para la salida, y JavaScript sería esencialmente el mismo. Puede usar pseudocontenido con el elemento adicional, pero realmente no es necesario.
Aprovechar el hecho de que el contenido de psuedo no se puede copiar también es inteligente. Por ejemplo, GitHub codifica la numeración de líneas de bloques con data-line-number=""
y ::before { content: attr(data-line-number); }
.
¡A nadie le gusta seleccionar números de línea cuando intenta copiar código! Buen uso aquí (probablemente incluso más flexible que los contadores de CSS), pero nuevamente, algo que las propiedades personalizadas de CSS también podrían manejar.
<td style="--line-num: 5"> ... </td>
Podría argumentar que esto es mejor porque si quisiera usar contadores CSS, podría usar ese primer valor para comenzar y no necesitarlo en cada línea.
Consulte la Numeración de líneas de lápiz de Chris Coyier (@chriscoyier) en CodePen.
Lo mismo ocurre con los trucos tipográficos que involucran la duplicación de texto en CSS por razones de estilo. Echa un vistazo a esta fantástica demostración de Mandy Michael usando attr()
. Estoy seguro de que te puedes imaginar como --heading: "Fracture";
podría hacer el truco allí.
La especificación de valores CSS3 (en la recomendación candidata) tiene una forma de hacer que attr () sea útil
No estoy seguro de que importe mucho, ya que yo diría que las propiedades personalizadas de CSS son un reemplazo casi total para attr()
, pero la especificación cubre específicamente esto, presumiblemente como un intento de hacerlo más útil.
La idea es establecer el tipo de valor a medida que lo toma en CSS.
<div data-color="red">Some Words</div>
div {
color: attr(data-color color);
}
O…
<span data-size="50">span</span>
span {
font-size: attr(data-size px);
}
Pero por lo que puedo decir, ningún navegador admite esto.