Почему размер `1vh` CSS соответствует разному размеру пикселя на экране - PullRequest
7 голосов
/ 10 марта 2020

У меня три div с одинаковыми высотами, равными 1vh`.

Моя проблема в том, что они отображаются с разным размером пикселя на экране. Иногда они выглядят одинаково, а иногда нет, особенно это происходит после изменения размера области просмотра. Пожалуйста, запустите фрагмент, чтобы увидеть.

.samples {
  display:flex;
}

.container{
  display:flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  margin:10px 20px;
  height: 20vh;
  width:20vh;
}

.container div{
  background: #000;
  width:100%;
}

#set1 div{
  height:.3vh;
}

#set2 div{
  height:.7vh;
}

#set3 div{
  height:.9vh;
}

#set4 div{
  height:1.1vh;
}
<div class = "samples">

  <div class="container" id="set1" >
    <div></div>
    <div></div>
    <div></div>
  </div>

  <div class="container" id="set2" >
    <div></div>
    <div></div>
    <div></div>
  </div>

  <div class="container" id="set3" >
    <div></div>
    <div></div>
    <div></div>
  </div>
  
    <div class="container" id="set4" >
    <div></div>
    <div></div>
    <div></div>
  </div>
  
</div>
<div>
<h4>Above are four samples, each sample includes 3 identical div.</h4>
<h4>But depends on your screen size you may not see what expected</h4>
</div>

Я сделал несколько снимков экрана для демонстрации того, что действительно происходит во время изменения размера, поскольку вы можете видеть div изображения с разной высотой, несмотря на то, что все они имеют 1vh высоту .

enter image description here

Если я вычислю 1vh вручную в javascript и введу он округляется с «px» до CSS, тогда он отлично работает. (В фрагменте я использовал .3, .7, .9, 1.1 vh для демонстрации)

  
  const set1Height = Math.round(document.documentElement.clientHeight * .3 / 100);
  const set2Height = Math.round(document.documentElement.clientHeight * .7 / 100);
  const set3Height = Math.round(document.documentElement.clientHeight * .9 / 100);
  const set4Height = Math.round(document.documentElement.clientHeight * 1.1 / 100);
  

  document.documentElement.style.setProperty("--set1-height", `${set1Height}px`);
  document.documentElement.style.setProperty("--set2-height", `${set2Height}px`);
  document.documentElement.style.setProperty("--set3-height", `${set3Height}px`);
  document.documentElement.style.setProperty("--set4-height", `${set4Height}px`);
  
.samples {
  display:flex;
}

.container{
  display:flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  margin:10px 20px;
  height: 20vh;
  width:20vh;
}

.container div{
  background: #000;
  width:100%;
}

#set1 div{
  height: var(--set1-height);
}

#set2 div{
  height: var(--set2-height);
}

#set3 div{
  height: var(--set3-height);
}

#set4 div{
  height: var(--set4-height);
}
<div class = "samples">

  <div class="container" id="set1" >
    <div></div>
    <div></div>
    <div></div>
  </div>

  <div class="container" id="set2" >
    <div></div>
    <div></div>
    <div></div>
  </div>

  <div class="container" id="set3" >
    <div></div>
    <div></div>
    <div></div>
  </div>
  
    <div class="container" id="set4" >
    <div></div>
    <div></div>
    <div></div>
  </div>
  
</div>
<div>
<h4>Here, after calculating heights and round them to `px` they looks identical</h4>
</div>

Моя первая мысль заключалась в округлении чисел с плавающей точкой, но если это так, то CSS округляет одно число с плавающей точкой до трех разных чисел ?

У меня вопрос, почему это происходит, и есть ли какое-нибудь чистое CSS решение для безопасного использования размеров области просмотра и уверенности в том, что они всегда выглядят как ожидалось?

Ответы [ 4 ]

7 голосов
/ 01 мая 2020

Проблема, с которой вы здесь сталкиваетесь, не в слое CSS, а на более низком уровне - в движке рендеринга браузера и, в некоторой степени, в физическом оборудовании дисплея.

почему CSS округляет одно число с плавающей точкой до трех разных чисел?

Это неправильно - CSS ведет себя правильно и выдает точно такое же значение высоты для все три деления в каждом наборе. Вы можете убедиться в этом, проверив элементы в инструментах разработчика и посмотрев рассчитанное свойство высоты для каждого элемента div.

Однако это значение не в целых пикселях, а в долях пикселя. И вы столкнулись с проблемой classi c в компьютерной графике - как вы отображаете доли пикселя на дисплее с дискретными пикселями?

Краткий ответ - Вы не можете , отлично. Вот почему эти три дробных делителя высоты пикселей в конечном итоге отображаются на том, что выглядит как разной высоты, когда вы изменяете их размеры и даже перемещаете их на экране. Это движок рендеринга, который делает все возможное, чтобы они выглядели одинаково, с разными результатами.

Причина, по которой работает ваше решение «округления» в JS, заключается в том, что оно округляет эти высоты до целых значений пикселей! Когда значения пикселей округлены, все гораздо проще выровнять (в наивном случае, если нет дробного отступа пикселей, margin et c между делителями), и вы с меньшей вероятностью увидите различия.

Попробуй! Если вы удалите Math.round или даже просто добавите 0.75 или что-то к округленному результату, вы увидите точно такую ​​же проблему с вашим решением JS, даже если все вычисленные значения, очевидно, идентичны.

Опять же, проблема не в том, что значения отличаются, а в том, что они отображаются по-разному вашим браузером / оборудованием. Единственный универсально «безопасный» обходной путь состоит в том, чтобы гарантировать, что значения на самом деле являются круглыми пиксельными значениями.

Вводя к этому вопросу:

есть ли чистое CSS решение для безопасного используйте размеры области просмотра

С учетом вышесказанного, получение округленных значений пикселей, к сожалению, нет . С помощью CSS calc() иным способом нельзя округлять результаты динамически.

В качестве общего предложения, если вам требуется точный рендеринг до тонких линий до пикселя и т. Д. c, отзывчивый CSS вероятно, это не тот инструмент, который вы хотите использовать. Вы, вероятно, хотите придерживаться статических c значений пикселей, но если вам действительно нужно, чтобы вещи были динамичными c и увеличивались и уменьшались при изменении размера области просмотра, тогда да, вероятно, вы захотите задействовать JS для большего управление рендерингом.

2 голосов
/ 01 мая 2020

Для меня это выглядит следующим образом. Результат отличается на 1px. Это объясняется тем, что вычисленная высота div не является целым числом, это число с плавающей запятой и значениями подпикселей. И экран не может отображать субпиксели. Таким образом, это зависит от позиции на экране, если браузер решит округлить до более низкого или более высокого значения.

enter image description here

1 голос
/ 10 марта 2020

Я решил это, используя 'px' вместо 'vh'

.container div{
  background: #000;
  width:100%;
  height:6px;
}

Так как, 'vh' Относительно высоты области просмотра, поэтому он может колебаться при изменении размера область просмотра.

• «px» - абсолютная единица измерения; но 'vh' является относительной единицей.

0 голосов
/ 02 мая 2020

это странно, но это всегда работает для меня, используйте vw также для высоты и ширины. а также попробуйте min-height

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...