¿Cómo puedo evitar la superposición de consultas de medios?

La cascada es lo que hace que CSS sea especial y poderoso. Pero en el caso de las consultas de los medios, la superposición puede parecer problemática.

Considere el siguiente CSS ( reglas continuas para la superposición de consultas de medios CSS ):

/* Standard - for all screens below 20em */ body { color: black; font-size: 1em; } /* Query A - slightly wider, mobile viewport */ @media (min-width: 20em) and (max-width: 45em) { body { color: red; } /* supposed to be unique for this width */ } /* Query B - everything else */ @media (min-width: 45em) { body { font-size: larger; } /* because viewport is bigger */ } 

Entonces, cuando la pantalla tiene exactamente 45m de ancho, la superposición en 45em será tratada de acuerdo con la cascada estándar de CSS:

  • Todas las definiciones de max-width: 45em se aplicarán primero,
  • y todo min-width: 45em se aplicará a partir de entonces.

Considere estas dos condiciones:

  • Todo el texto normalmente sería black , pero Query A es único y tiene color: red .
  • Como Query B es para viewports más grandes, su texto tiene el font-size: larger CSS font-size: larger .

Por lo tanto, con un ancho de exactamente 45em, obtendríamos texto grande y rojo . ¿Cuál sería la mejor solución para evitar esto?


Veo dos posibilidades:

  1. Vuelva a declarar el texto para que tenga color: black en la Consulta B , pero luego administrará dos declaraciones si elige cambiar el color en el futuro. (Por supuesto, no es un problema con esta única línea de código, pero imagine que hay muchas otras declaraciones y selectores).

  2. Evite la superposición mediante el uso de valores de píxeles como max-width: 799px y min-width: 800px , pero luego está usando píxeles, supongo que podrían ser 49.9375em y 50em, respectivamente. ¿Pero qué pasa si el valor predeterminado ya no es 16em y se redondea algo? Y aún no estamos seguros de lo que sucede en esa brecha. (¿Un agujero negro que rompe el continuo espacio-tiempo?)

Ambos tienen sus inconvenientes … ¿alguna otra idea?

La única forma confiable de crear dos bloques @media mutuamente excluyentes para cualquier consulta de medios dada es utilizarla para not negarla en uno de los bloques. Desafortunadamente, esto significa repetir su consulta de medios una vez para cada bloque @media . Entonces, en lugar de esto, por ejemplo:

 @media (max-width: 49.9375em) { body { color: red; } } @media (min-width: 50em) { body { font-size: larger; } } 

Tendría esto:

 /* * Note: Media Queries 4 still requires 'not' to be followed by a * media type (eg 'all' or 'screen') for reasons I cannot comprehend. */ @media not all and (min-width: 50em) { body { color: red; } } @media (min-width: 50em) { body { font-size: larger; } } 

Demostración jsFiddle interactiva

Esto es muy efectivo para cerrar la brecha con las características de los medios de rango como el width y height ya que esencialmente convierte esto en un escenario de uno u otro. Pero, al igual que sus dos primeras opciones, no es perfecto: como se mencionó, debe repetir la misma consulta de medios dos veces y agregar not a una de ellas. No existe una construcción if / else para @media como se describe en las Reglas condicionales 3 .


Aunque menciono esto en mi respuesta a su pregunta anterior:

Según mis experimentos, Safari en iOS redondea todos los valores de píxels fraccionarios para asegurar que max-width: 799px uno de max-width: 799px y min-width: 800px , incluso si la ventana gráfica es realmente 799.5px (que aparentemente coincide con la anterior).

Debe notarse, aún, que he notado algunos caprichos cuando se trata de redondear. Dicho esto, no he podido encontrar un valor fraccionario que evadiría las consultas de los medios y terminase por no recibir estilos de ningún conjunto de reglas (lo que, por cierto, es lo peor que puede pasar, así que no se preocupe) sobre la posibilidad de crear una brecha espacio-temporal). Eso debe significar que los navegadores, al menos, Safari, como yo he probado, hacen un trabajo razonable para garantizar que satisfagan las consultas de los medios, incluso si tiene valores que difieren (exactamente en 1 píxel CSS).

Sin embargo, cuando se trata de unidades con espacios más grandes que se pueden observar en los navegadores de escritorio, como el ccsme, hay un margen de error mucho mayor. Por ejemplo, un comentario sugiere usar 49.99999em en lugar de algo más arbitrario que 49.9375em, pero aparentemente hay una diferencia, al menos con un tamaño de letra predeterminado de 16px.

Simplifiqué tu código, cambié las consultas de medios para usar valores decimales y puse el código en jsFiddle:

 @media (max-width: 49.9375em) { body { color: red; } } @media (min-width: 50em) { body { font-size: larger; } } 

Si cambia el tamaño del panel de resultados a exactamente 800 píxeles (el texto se actualizará para guiarlo), en realidad terminará con diferentes resultados dependiendo de si se usa @media (max-width: 49.99999em) @media (max-width: 49.9375em) o @media (max-width: 49.99999em) (también me sorprendió esto) …

De cualquier manera, tienes razón: la opción 2 también tiene sus inconvenientes. No soy particularmente aficionado, para ser sincero, porque no me gustaría descifrar las peculiaridades del dispositivo y del agente de usuario que están fuera de mi control. Si eres como yo, supongo que sería mejor pasar por la inconveniencia de redeclarar tus reglas a un costo (?) De estar más atento a tu código, ya que al menos eso todavía está bajo tu control como autor.

Para mí, la mejor manera es mantener un espacio de 0.01em:

 @media (min-width: 20em) and (max-width: 44.99em) { body { color: red; } /* supposed to be unique for this width */ } @media (min-width: 45em) { body { font-size: larger; } /* because viewport is bigger */ } 

Le recomiendo que lea este artículo para obtener detalles y comparar las diferentes soluciones para evitar la superposición de consultas de medios .

Saludos, Thomas.