Как избежать перекрытия медиа-запросов?

каскад-это то, что делает CSS особенным и мощным. Но в случае медиа-запросов перекрытие can представляется проблематичным.

рассмотрим следующий CSS (продолжение правила перекрытия медиа-запросов 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 */
}

так когда экран точно 45em широко, перекрытие на 45em будет рассматриваться согласно стандартному каскаду CSS:

  • все max-width: 45em определения будут применены во-первых,
  • и min-width: 45em будет применяться в дальнейшем.

рассмотрим эти два условия:

  • весь текст обычно black, а Запрос A является уникальным и имеет color: red.
  • С Запрос B для больших видовых экранов, это текст имеет CSS font-size: larger.

поэтому, на ширине ровно 45em, мы получили бы большой и красный текст. что бы лучшее решение, чтобы избежать этого?


Я вижу два варианта:

  1. повторно объявить текст для color: black на Запрос B, но тогда вы управляете двумя объявлениями, если вы решите изменить color в будущем. (Конечно, не такая проблема с этой единственной строкой кода, но представьте, что есть много других объявлений и селекторов.)

  2. избегайте перекрытия, используя значения пикселей, такие как max-width: 799px и min-width: 800px, но тогда вы используете пиксели-я думаю, они могут быть 49.9375 em и 50em соответственно. Хотя что, если по умолчанию больше не 16em и что-то округляется? И мы все еще не уверен что происходит в этот промежуток. (Черная дыра, разрывающая пространственно-временной континуум?)

у обоих есть свои недостатки... есть другие идеи?

2 ответов


единственный надежный способ создать два взаимоисключающих @media блоки для любого заданного медиа-запроса должны использовать not чтобы отрицать это в одном из блоков. К сожалению, это означает повторение медиа-запроса один раз для каждого @media заблокировать. Итак, вместо этого, например:

@media (max-width: 49.9375em) {
    body {
        color: red;
    }
}

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

у вас будет это:

/* 
 * Note: Media Queries 4 still requires 'not' to be followed by a
 * media type (e.g. '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;
    }
}

интерактивная демонстрация jsFiddle

это очень эффективно на закрывать зазор с характеристиками средств ряда как width и height поскольку это по существу превращает это в сценарий "или-или". Но, как и ваши первые два варианта, он не идеален: как уже упоминалось, вы должны повторить один и тот же медиа-запрос дважды и добавить not одной из них. Нет конструкции if/else для @media как описано в Условные Правила 3.


хотя я упоминаю об этом в своем ответе на ваш предыдущий вопрос:

из моих экспериментов казалось бы Safari на iOS округляет все дробные значения пикселей, чтобы гарантировать, что один из max-width: 799px и min-width: 800px будет соответствовать, даже если окно просмотра действительно 799.5 px (что, по-видимому, соответствует первому).

следует отметить, что я заметил некоторые причуды, когда дело доходит до округления. Тем не менее, я не смог найти дробное значение, которое бы уклонялось и медиа-запросы и в конечном итоге не получают стили из любого набора правил (что, кстати, является худшим, что может произойти,поэтому не беспокойтесь о потенциальном создании пространственно-временного разлома). Это должно означать, что браузеры - по крайней мере, Safari, как я тестировал, - выполняют разумную работу по обеспечению удовлетворения медиа-запросов, даже если у вас есть значения, которые отличаются (ровно на 1 пиксель CSS).

когда дело доходит до единиц с большими пробелами, которые можно наблюдать в настольных браузерах, хотя, как ems, существует гораздо больший запас ошибок. Например, один комментарий предлагает использовать 49.99999 em вместо чего-то большего произвольно, чем 49.9375 em, но, по-видимому, есть разница, по крайней мере, с размером шрифта по умолчанию 16px.

я упростил ваш код, изменил медиа-запросы на использование десятичных значений и поместил код в jsFiddle:

@media (max-width: 49.9375em) {
    body {
        color: red;
    }
}

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

если вы измените размер панели результатов ровно на 800 пикселей (текст будет обновляться, чтобы направлять вас), вы фактически получите разные результаты в зависимости от того,@media (max-width: 49.9375em) используется или @media (max-width: 49.99999em) используется (I был удивлен этим тоже)...

в любом случае, вы правы: вариант 2 тоже имеет свои недостатки. Честно говоря, мне это не особенно нравится, потому что я не хотел бы ломать голову над причудами устройства и агента пользователя, которые находятся вне моего контроля. Если вы похожи на меня, я полагаю, было бы лучше пройти через неудобства, объявляя свои правила за счет (?) быть более бдительным вокруг вашего кода, так как это, по крайней мере, все еще находится под вашим контролем как автора.


для меня лучший способ-сохранить разрыв 0.01 em:

@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 */
}

Я рекомендую вам прочитать эту статью для деталей и сравнения различные решения для предотвращения перекрытия медиа-запросов.

Ура, Томас.