Uso de detección de funciones, condicionales y grupos con selectores

Índice
  1. Cuando es necesaria la detección de características
  2. Soporte de selector condicional
  3. Contraparte selectora de @supports
  4. Grupos de propiedades fundamentales de selectores.
  5. Ejemplo del mundo real
  6. Fiabilidad y limitaciones de esta técnica.

CSS está diseñado de una manera que permite la adición relativamente fluida de nuevas funciones. Desde los bordes del lenguaje, las especificaciones han requerido que los navegadores ignoren elegantemente cualquier propiedad, valor, selector o regla que no admitan. En consecuencia, en la mayoría de los casos, es posible utilizar con éxito una tecnología más nueva sin causar ningún problema en los navegadores más antiguos.

Considere la propiedad relativamente nueva caret-color(cambia el color del cursor en las entradas). Su soporte sigue estando bajo pero eso no significa que no debamos utilizarlo hoy en día.

.myInput {  color: blue;  caret-color: red;}

Observa cómo lo colocamos justo al lado de color, una propiedad con soporte de navegador prácticamente universal; uno que se aplicará en todas las partes. En este caso, no hemos discriminado limpiamente entre navegadores modernos y antiguos. A cambio, simplemente confiamos en que los más antiguos ignoran las funciones que no admiten.

Resulta que este patrón es lo suficientemente poderoso en la gran mayoría de situaciones.

Cuando es necesaria la detección de características

En algunos casos, sin embargo, nos gustaría mucho utilizar una propiedad moderna o un valor de propiedad cuyo uso difiera significativamente de su alternativa. En esos casos, @supportsviene al rescate.

@supportses una regla especial que nos permite aplicar condicionalmente cualquier estilo en los navegadores que admitan una propiedad particular y su valor.

@supports (display: grid) {  /* Styles for browsers that support grid layout... */}

Funciona de manera análoga a @medialas consultas, que además solo aplican estilos de forma condicional cuando se cumple un determinado predicado.

Para ilustrar el uso de @supports, considere el siguiente ejemplo: nos gustaría mostrar un avatar subido por un usuario en un bonito círculo, pero no podemos garantizar que el archivo real tenga dimensiones cuadradas. Para eso, la object-fitpropiedad sería de gran ayuda; Sin embargo, Internet Explorer (IE) no lo admite. ¿Qué hacemos entonces?

Comenzamos con el marcado:

div  img src="..." alt="..." //div

Como alternativa no tan bonita, reduciremos el ancho de la imagen dentro del avatar a costa de que los archivos más anchos no cubran completamente el área del avatar. En cambio, nuestro fondo de un solo color aparecerá debajo.

.avatar {  position: relative;  width: 5em;  height: 5em;  border-radius: 50%;  overflow: hidden;  background: #cccccc; /* Fallback color */}.avatar-image {  position: absolute;  top: 50%;  right: 0;  bottom: 0;  left: 50%;  transform: translate(-50%, -50%);  max-width: 100%;}

Puedes ver este comportamiento en acción aquí:

Observa que hay una imagen cuadrada, una ancha y otra alta.

Ahora, si usamos object-fit, podemos dejar que el navegador decida la mejor manera de posicionar la imagen, es decir, si estirar el ancho, el alto o ninguno de los dos.

@supports (object-fit: cover) {  .avatar-image {    /* We no longer need absolute positioning or any transforms */    position: static;    transform: none;    object-fit: cover;    width: 100%;    height: 100%;  }} 

El resultado, para el mismo conjunto de dimensiones de imagen, funciona muy bien en los navegadores modernos:

Soporte de selector condicional

Aunque la especificación Selectores Nivel 4 todavía es un Borrador de Trabajo, algunos de los selectores que definen, como por ejemplo :placeholder-shown, ya son compatibles con muchos navegadores. Si esta tendencia continúa (y si el borrador conserva la mayoría de sus propuestas actuales), este nivel de especificación introducirá más selectores nuevos que cualquiera de sus predecesores. Mientras tanto, y también mientras IE sigue vivo, los desarrolladores de CSS tendrán que apuntar a un espectro aún más diverso y volátil de navegadores con soporte incipiente para estos selectores.

Será muy útil para realizar la detección de funciones en los selectores. Desafortunadamente, @supportssólo está diseñado para probar el soporte de propiedades y sus valores, e incluso el borrador más reciente de su especificación no parece cambiar eso. Sin embargo, desde sus inicios, ha definido una regla de producción especial en su gramática cuyo único propósito es proporcionar espacio para posibles extensiones compatibles con versiones anteriores y, por lo tanto, es perfectamente factible que una versión futura agregue la capacidad de condicionar el soporte. . . para selectores particulares. Sin embargo, esa eventualidad sigue siendo totalmente hipotética.

Contraparte selectora de @supports

En primer lugar, es importante enfatizar que, de manera análoga al caret-colorejemplo mencionado anteriormente donde @supportsprobablemente no sea necesario, muchos selectores no necesitan ser probados claramente para ninguno de los dos. Por ejemplo, podríamos simplemente intentar hacer Amarillento ::selectiony no preocuparnos por los navegadores que no lo admiten, ya que no será el fin del mundo si la apariencia de selección sigue siendo la predeterminada del navegador.

Sin embargo, hay casos en los que sería muy deseable la detección específica de características para los selectores. En el resto de este artículo, presentaremos un patrón para abordar dichas necesidades y posteriormente lo usaremos para :placeholder-showncrear una alternativa solo CSS al campo de texto Material Design con una etiqueta flotante.

Grupos de propiedades fundamentales de selectores.

Para evitar duplicaciones, es posible condensar varias declaraciones idénticas en una lista de selectores separada por comas, a la que se hace referencia como grupo de selectores.

Así podemos girar:

.foo { color: red }.bar { color: red }

…es:

.foo, .bar { color: red }

Sin embargo, como advierte la especificación de Selectores de nivel 3, estos solo son equivalentes porque todos los selectores involucrados son válidos. Según la especificación, si alguno de los selectores del grupo no es válido, se ignora todo el grupo. En consecuencia, los selectores:

..foo { color: red } /* Note the extra dot */.bar { color: red }

…no se pudo agrupar de forma segura, ya que el selector anterior no es válido. Si los agrupamos, provocaríamos que el navegador también ignorara la declaración de este último.

Vale la pena señalar que, en lo que respeta a un navegador, no hay diferencia entre un selector no válido y un selector que solo es válido según una versión más reciente de la especificación o uno que el navegador no conoce. Para el navegador, ambos son simplemente inválidos.

Podemos aprovechar esta propiedad para probar la compatibilidad con un selector en particular. Todo lo que necesitamos es un selector que no podemos garantizar que no coincide con nada. En nuestros ejemplos, usaremos :not(*).

.foo { color: red }:not(*):placeholder-shown,.foo {  color: green}

Analizamos lo que sucede aquí. Un navegador más antiguo aplicó correctamente la primera regla, pero al procesar el resto, encontrará que el primer selector del grupo no es válido porque no lo conoce :placeholder-shown, y por lo tanto ignorará todo el grupo de selectores. En consecuencia, todos los elementos que coincidirán .foopermanecerán en red. Por el contrario, mientras un navegador más nuevo probablemente pondrá los ojos en blanco al buscar :not(*)(que nunca coincidirá con nada), no descartará todo el grupo de selectores. En cambio, se anulará la regla anterior y, por lo tanto, todos los elementos que coincidirán .fooserán green.

Observe la similitud @supports(o cualquier @mediaconsulta, de hecho) en términos de cómo se usa. Primero especificamos el respaldo y luego lo anulamos para los navegadores que satisfacen un predicado, que en este caso es el soporte para un selector particular, aunque escrito de una manera algo complicada.

Ejemplo del mundo real

Podemos usar esta técnica para nuestra entrada con una etiqueta flotante para separar los navegadores que lo hacen de los que no lo admiten :placeholder-shown, una pseudoclase que es absolutamente vital para este ejemplo. En cuanto a una relativa simplicidad, a pesar de las mejores prácticas de interfaz de usuario, elegiremos nuestro recurso alternativo para que sea solo el marcador de posición real.

Comenzamos con el marcado:

div  input type="email" name="email" placeholder="Email" required /  label for="email"Email/label/div

Como antes, la clave es agregar primeros estilos para navegadores más antiguos. Ocultamos la etiqueta y configuramos el color del marcador de posición.

.input {  height: 3.2em;  position: relative;  display: flex;  align-items: center;  font-size: 1em;}.input-control {  flex: 1;  z-index: 2; /* So that it is always "above" the label */  border: none;  padding: 0 0 0 1em;  background: transparent;  position: relative;}.input-label {  position: absolute;  top: 50%;  right: 0;  bottom: 0;  left: 1em; /* Align this with the control's padding */  z-index: 1;  display: none; /* Hide this for old browsers */  transform-origin: top left;  text-align: left;}  

Para los navegadores modernos, podemos desactivar efectivamente el marcador de posición configurándolo coloren transparent. También podemos alinear el inputy el labelrelativo entre sí para cuando se muestre el marcador de posición. Con eso fin, también podemos utilizar el selector de hermanos para diseñarlo labelcon respecto al estado del archivo input.

.input-control:placeholder-shown::placeholder {  color: transparent;}.input-control:placeholder-shown ~ .input-label {  transform: translateY(-50%)}.input-control:placeholder-shown {  transform: translateY(0);}

¡Por fin el truco! Exactamente como arriba, anulamos los estilos para labely inputpara los navegadores modernos y el estado en el que no se muestra el marcador de posición. Eso implica apartarlo labely reducirlo un poco.

:not(*):placeholder-shown,.input-label {  display: block;  transform: translateY(-70%) scale(.7);}:not(*):placeholder-shown,.input-control {  transform: translateY(35%);}

Con todas las piezas juntas, así como más estilos y opciones de configuración ortogonales a este ejemplo, puedes ver la demostración completa:

Fiabilidad y limitaciones de esta técnica.

Básicamente, esta técnica requiere un selector que no coincida con nada. Para ello, hemos estado utilizando :not(*); Sin embargo, su apoyo también es limitado. El selector universal *es compatible incluso con IE 7, mientras que la :notpseudoclase sólo se ha implementado desde IE 9, que es, por tanto, el navegador más antiguo en el que funciona este enfoque. Los navegadores más antiguos rechazarían nuestros grupos de selección por el motivo equivocado: ¡no son compatibles :not! Alternativamente, podríamos usar un selector de clase como .fooo un selector de tipo como foo, soportando así incluso los navegadores más antiguos. Sin embargo, estos hacen que el código sea menos legible ya que no transmiten que nunca deben coincidir con nada y, por lo tanto, para la mayoría de los sitios modernos, :not(*)parece la mejor opción.

En cuanto a si la propiedad de los grupos de selectores que hemos estado aprovechando también se mantiene en los navegadores más antiguos, el comportamiento se ilustra en un ejemplo como parte de la sección CSS 1 sobre análisis compatible con versiones posteriores. Además, la especificación CSS 2.1 exige claramente este comportamiento. Para poner en perspectiva la antigüedad de esta especificación, esto es lo que se introdujo :hover. En resumen, si bien esta técnica no se ha probado exhaustivamente en los navegadores más antiguos u oscuros, su soporte debería ser extremadamente amplio.

Por último, hay una pequeña salvación para los usuarios de Sass (Sass, no SCSS): al encontrar el :not(*):placeholder-shownselector, el compilador se deja engañar por los dos puntos iniciales, intenta analizarlo como una propiedad y, cuando encuentra el error, le aconseja al usuario que lo haga. desarrollador que escapa del selector de la siguiente manera: :not(*):placeholder-shown, lo que no parece muy agradable. Una mejor solución alternativa es quizás reemplazar la barra invertida con otro selector universal para obtener *:not(*):placeholder-shown, ya que, según la especificación, está implícito de todos los modos en este caso.

SUSCRÍBETE A NUESTRO BOLETÍN 
No te pierdas de nuestro contenido ni de ninguna de nuestras guías para que puedas avanzar en los juegos que más te gustan.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir

Este sitio web utiliza cookies para mejorar tu experiencia mientras navegas por él. Este sitio web utiliza cookies para mejorar tu experiencia de usuario. Al continuar navegando, aceptas su uso. Mas informacion