Неверный стек с коробкой-тенью и трансформацией


Я создал фигуру, которая представляет собой страницу с тенью, которая становится больше к нижней части.

body {
  background: #dddddd;
}
div {
  background: white;
  margin: 40px auto;
  height: 300px;
  width: 300px;
  position: relative;
  padding: 10px;
}
div:before,
div:after {
  height: 96%;
  z-index: -10;
  position: absolute;
  content: "";
  left: 8px;
  top: 2%;
  width: 30%;
  max-width: 300px;
  background: transparent;
  box-shadow: -10px 0px 10px rgba(0, 0, 0, 0.5);
  transform: rotate(1.5deg);
}
div:after {
  transform: rotate(-1.5deg);
  right: 8px;
  left: auto;
  box-shadow: 10px 0px 10px rgba(0, 0, 0, 0.5);
}
<div></div>
Мне нужно, чтобы это было повернуто, но когда я пытаюсь добавить transform: rotate(10deg), иллюзия box-shadow разрушается и идет поверх родительского слоя.

body {
  background: #dddddd;
}
div {
  background: white;
  margin: 40px auto;
  height: 300px;
  width: 300px;
  position: relative;
  padding: 10px;
  transform: rotate(10deg);
}
div:before,
div:after {
  height: 96%;
  z-index: -10;
  position: absolute;
  content: "";
  left: 8px;
  top: 2%;
  width: 30%;
  max-width: 300px;
  background: transparent;
  box-shadow: -10px 0px 10px rgba(0, 0, 0, 0.5);
  transform: rotate(1.5deg);
}
div:after {
  transform: rotate(-1.5deg);
  right: 8px;
  left: auto;
  box-shadow: 10px 0px 10px rgba(0, 0, 0, 0.5);
}
<div></div>

Я нашел этот вопрос: какие свойства CSS создают контекст укладки? но, кажется, нет предложенного решения для моего требование.

Есть ли какие-либо хорошие решения, которые будут работать в моем случае? Я не возражаю, если они есть SVG, filter, canvas или любая другая вещь, если она поддерживается достаточно хорошо.
3 5

3 ответа:

Примечание: Этот ответ не описывает, как исправить проблему контекста укладки, которая видна в вашем подходе. Это всего лишь несколько альтернативных подходов, которые могут быть использованы для достижения аналогичного эффекта. преимущество этих подходов заключается в том, что онидолжны работать в IE10+ и не требуют каких-либо дополнительных элементов .

Я бы все равно рекомендовал ответ vals, если поддержка IE не является обязательной.

Метод 1: Перспектива Transform

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

body {
  background: #dddddd;
}
div {
  position: relative;
  height: 300px;
  width: 300px;
  padding: 10px;
  margin: 40px auto;
  transform: rotate(10deg);
}
div:before,
div:after {
  position: absolute;
  content: '';
  top: 0px;
}
div:before {
  height: 100%;
  width: 100%;
  left: 0px;
  background: white;
}
div:after {
  height: 98%;
  width: 97%;
  left: 1.5%;
  transform-origin: bottom;
  transform: perspective(125px) rotateX(1deg);
  box-shadow: 10px 0px 10px rgba(0, 0, 0, .5), -10px 0px 10px rgba(0, 0, 0, .5);
  z-index: -1;
}
<div></div>

Метод 2: Линейные Градиенты

Мы можем использовать фоновые изображения linear-gradient и расположить их соответствующим образом, чтобы произвести эффект, подобный произведенному у ящика-тени. Но, как вы можете видеть на выходе, он не совсем соответствует тени, потому что размытые области не совпадают.

Здесь мы используем следующее:

  • одно небольшое угловое линейное градиентное изображение (to top left) для получения тени на левой стороне коробки.
  • Еще одно небольшое угловое линейное градиентное изображение (to top right) для получения тени на правой стороне коробки.
  • большое линейно-градиентное изображение для области белого цвета (которая является почти сплошной цвет). Здесь вместо сплошного цвета используется градиент, поскольку размер градиентного изображения можно регулировать.

body {
  background: #dddddd;
}
div {
  margin: 40px auto;
  height: 300px;
  width: 300px;
  transform: rotate(10deg);
  backface-visibility: hidden;
  background: linear-gradient(to right, transparent 0.1%, white 0.1%), linear-gradient(to top left, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, .3) 5%, transparent 50%), linear-gradient(to top right, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, .3) 5%, transparent 50%);
  background-size: 280px 100%, 10px 97%, 10px 97%;
  background-position: 10px 0px, left top, right top;
  background-repeat: no-repeat;
  background-origin: border-box;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div></div>

Нижняя часть градиента все еще не получает размытия, которое видно на выходе box-shadow. При необходимости это может быть достигнуто в некоторой степени путем добавления еще большего количества градиентов, как в приведенном ниже фрагменте.

body {
  background: #dddddd;
}
div {
  margin: 40px auto;
  height: 300px;
  width: 300px;
  transform: rotate(10deg);
  backface-visibility: hidden;
  background: linear-gradient(to right, transparent 0.1%, white 0.1%), linear-gradient(to top left, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, .3) 5%, transparent 50%), linear-gradient(to top right, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, .3) 5%, transparent 50%), linear-gradient(to bottom left, rgba(0, 0, 0, 0), rgba(0, 0, 0, .3) 5%, transparent 60%), linear-gradient(to bottom right, rgba(0, 0, 0, 0), rgba(0, 0, 0, .3) 5%, transparent 70%);
  background-size: 280px 100%, 10px 97%, 10px 97%, 10px 2.5%, 10px 2.5%;
  background-position: 10px 0px, left top, right top, left 99.25%, right 99.25%;
  background-repeat: no-repeat;
  background-origin: border-box;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div></div>

Если вы используете другой div, это устраняет проблему, которую вы испытываете, так что цвет фона находится на внутреннем div, а поворот-на внешнем div.

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

body {
  background: #dddddd;
}
.two{
background: white;
height: 300px;
width: 300px;
padding: 10px;
}
div.one {
  margin: 40px auto;
  height: 300px;
  width: 300px;
  position: relative;
  
  transform: rotate(10deg);
}
div.one:before,
div.one:after {
  height: 96%;
  z-index: -10;
  position: absolute;
  content: "";
  left: 8px;
  top: 2%;
  width: 30%;
  max-width: 300px;
  background: transparent;
  box-shadow: -10px 0px 10px rgba(0, 0, 0, 0.5);
  transform: rotate(1.5deg);
}
div.one:after {
  transform: rotate(-1.5deg);
  right: 8px;
  left: auto;
  box-shadow: 10px 0px 10px rgba(0, 0, 0, 0.5);
}
<div class="one">
<div class="two">
</div>
</div>

Когда вы войдете в мир трансформаций, сами трансформации решат некоторые из проблем, которые они создают. Вы можете решить эту задачу с помощью 3d-эквивалента z-индекса, координаты Z

К сожалению, это не будет работать в IE (я считаю, пока они не поддерживают сохранить 3d)

body {
  background: #dddddd;
}
div {
  background: white;
  margin: 40px auto;
  height: 300px;
  width: 300px;
  position: relative;
  padding: 10px;
  transform: translateZ(1px) rotate(10deg);
  transform-style: preserve-3d;
}
div:before,
div:after {
  height: 96%;
  z-index: -10;
  position: absolute;
  content: "";
  left: 8px;
  top: 2%;
  width: 30%;
  max-width: 300px;
  background: transparent;
  box-shadow: -10px 0px 10px rgba(0, 0, 0, 0.5);
  transform: translateZ(-1px) rotate(1.5deg);
}
div:after {
  transform: translateZ(-1px) rotate(-1.5deg);
  right: 8px;
  left: auto;
  box-shadow: 10px 0px 10px rgba(0, 0, 0, 0.5);
}
<div></div>