Статьи

Освоение CSS3 нескольких фонов

Наше путешествие в мир теней CSS3 продолжается. Сегодня мы сосредоточимся на еще одной интересной функции — как использовать несколько фонов с CSS3.

Фоновая композиция

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

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

Я полагаю, у вас могут быть другие разумные аргументы. ?

Классический подход

Поэтому нам нужно создать многослойный фон, поместив некоторые изображения поверх других. Как обычно решается эта проблема? Это действительно просто: просто создайте контейнер (например, элемент div) для каждого имеющегося изображения и добавьте для него фон, используя правило CSS. Затем вы вставляете один контейнер в другой или помещаете их в ряд и применяете соответствующие правила позиционирования CSS. У меня есть простой пример:

<div class="sample1">
  <div class="sea">
    <div class="mermaid"><div class="fishing"></div></div>
    <div class="fish"></div>
  </div>
</div>

Класс рыбалки внутри класса русалки только для демонстрационных целей.

И здесь у нас есть несколько стилей CSS:

.sample1 .sea, .sample1 .mermaid, .sample1 .fishing {
   height: 300px;
   width: 480px;
   position: relative;
}
.sample1 .sea {
   background: url(media/sea.png) repeat-x top left;
}
.sample1 .mermaid {
   background: url(media/mermaid.svg) repeat-x bottom left;
}
.sample1 .fish {
  background: url(media/fish.svg) no-repeat;
  height: 70px;
  width: 100px;
  left: 30px;
  top: 90px;
  position: absolute;
}
.sample1 .fishing {
  background: url(media/fishing.svg) no-repeat top right 10px;
}

 

Результат:

В этом примере у меня есть три вложенных div с фоновыми изображениями и еще один соседний div, fish. Вы можете представить, что рыбу можно анимировать с помощью JavaScript или CSS3-переходов или анимации.

Обратите внимание, что для класса рыбалки я использую новый синтаксис фонового позиционирования , определенный в CSS3. Но пока он поддерживается только IE9 + и Opera 11+; он еще не работает в Firefox 10 или Chrome 16. Таким образом, пользователи последних двух не могут поймать рыбу. ?

Давай продолжим. Можно ли упростить эту композицию?

Несколько фонов

Это когда несколько фонов приходят на сцену. Эта функция позволяет добавлять более одного фона одновременно к одному элементу. Вот как это выглядит:

<div class="sample2">
  <div class="sea">
    <div class="fish"></div>
  </div>
</div>

И стили:

.sample2 .sea {
  height: 300px;
  width: 480px;
  position: relative;
  background-image: url("media/fishing.svg"), url("media/mermaid.svg"), url("media/sea.png");
  background-position: top right 10px, bottom left, top left;
  background-repeat: no-repeat, repeat-x, repeat-x ;
}
.sample2 .fish {
  background: url("media/fish.svg") no-repeat;
  height: 70px;
  width: 100px;
  left: 30px;
  top: 90px;
  position: absolute;
}

Чтобы определить несколько фонов, вы должны использовать правило фонового изображения, перечисляя ваши изображения (через запятую). Вы также можете использовать другие правила для установки положения, режима повторения и других атрибутов для каждого изображения — просто запишите их также, используя разделенный запятыми список для соответствующего правила. Обратите внимание на порядок изображений: они перечислены слева направо, начиная с самого верхнего и заканчивая самым нижним.

Результат на 100% идентичен:

В одном правиле

Если вам не нужна ваша рыба, чтобы плавать в независимом блоке, весь фон может быть записан в одном простом правиле:

<div class="sample3">
  <div class="sea"></div>
</div>

Стили:

.sample3 .sea {
  height: 300px;
  width: 480px;
  position: relative;
  background-image:  url("media/fishing.svg"), url("media/mermaid.svg"), url("media/fish.svg"), url("media/sea.png");
  background-position: top right 10px, bottom left, 30px 90px, top left;
  background-repeat: no-repeat, repeat-x;
}

Я не показываю ту же картинку еще раз, но поверьте мне — она ​​равна двум изображениям выше. Посмотрите на стили еще раз, особенно на правило повторения фона. Согласно спецификации, если часть списка не указана, UA (браузер) должен повторить текущий список, чтобы заполнить остальные.

В нашем случае оно равно следующему определению:

background-repeat: no-repeat, repeat-x, no-repeat, repeat-x;

Более короткая версия

Если вы помните, в CSS2.1 можно описать фоновое изображение в одном коротком фоновом правиле. Как насчет нескольких фонов? На самом деле, вы также можете использовать правило фона для нескольких фонов:

.sample4 .sea {
  height: 300px;
  width: 480px;
  position: relative;
  background: url("media/fishing.svg") top right 10px no-repeat,
              url("media/mermaid.svg") bottom left repeat-x,
              url("media/fish.svg") 30px 90px no-repeat,
              url("media/sea.png") repeat-x;
}

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

Динамические изображения

Вот что мы уже знаем: если ваш фон в основном статичен — это может зависеть от размера контейнера (т. Е. Если вы используете% length, чтобы некоторые слои сместились при изменении размера окна), — тогда магия нескольких фонов полезна, так как действительно упрощает структуру страницы. Но что, если вам нужно анимировать некоторые слои с помощью JavaScript (перемещение, вращение и т. Д.)?

У меня есть образец из реальной жизни — тема одуванчиков на сайте Яндекса (российский поисковый провайдер, YNDX ):

Если вы посмотрите на исходный код (нажмите
F12 в IE, чтобы открыть devtools ), вы найдете такой код

<div class=b-skin-bg sizcache="272" sizset="0">
  ​<div class=b-fluff-bg sizcache="272" sizset="0">
​​    <div class=b-fluff__sky sizcache="272" sizset="0">
      ​​​<div style="background-position: 3244px 0px" class=b-fluff__cloud></div>
        ​​​<div style="width: 1200px" class=b-max-width sizcache="214" sizset="0">
          <div class=b-fluff__placeholder sizcache="302" sizset="0">
          <div style="bottom: 105px; display: none; left: 940px" class="b-fluff__item b-fluff_item_3" jQuery1328289994769="30"></div>
          ​​​​​<div style="bottom: 50px; display: none; left: 879px" class="b-fluff__item b-fluff_item_3" jQuery1328289994769="31"></div>
          ​​​​​<div style="bottom: 105px; display: none; left: 940px" class="b-fluff__item b-fluff_item_3" jQuery1328289994769="32"></div>
…
        ​​​​</div>
      </div>
    </div>
  </div>
</div>

В div с классами b-fluff-bg, b-fluff__cloud & b-fluff__item применяются правила CSS, в которые добавляются наложенные фоновые изображения. Фон с облачной прокруткой слева направо, а фон с семенами одуванчика летит по экрану.

Можно ли переписать такую ​​композицию, используя CSS3 несколько фонов? На самом деле, да, но только если 1) он поддерживается во всех целевых браузерах и 2) продолжить чтение;)

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

Для анимации нашего морского фона мы можем использовать следующий код JavaScript:

$(document).ready(function() {
  var sea = $(".sample5 .sea")[0];
  var fishesX = 30;
  var fishesY = 90;
  var fishX = 0;
  var fishY = 0;
  var mermaidX = 0;
  var t = 0;
  function animationLoop() {
      fishesY = 90 + Math.floor(30 * Math.sin(t++ / 180.0));
      if(--fishesX  480) mermaidX = 0;
      fishY = -10 + (10 * Math.cos(t * 0.091));
      fishX = 10 + (5 * Math.sin(t * 0.07));
      sea.style.backgroundPosition = "top " + fishY + "px right " + fishX + "px, " + mermaidX + "px bottom," + fishesX + "px " + fishesY + "px, top left";
      window.requestAnimFrame(animationLoop);
  }
  animationLoop();
});

Куда:

window.requestAnimFrame = (function() {
  return
      window.requestAnimationFrame ||
      window.msRequestAnimationFrame ||
      window.mozRequestAnimationFrame ||
      window.oRequestAnimationFrame ||
      window.webkitRequestAnimationFrame ||
      (function(callback) { window.setTimeout(callback, 1000 / 60); });
})();

Результат ( видео ):

Вы также можете использовать CSS3 Transitions или Animations, но это хорошая тема для отдельного обсуждения.

Параллакс и Интерактивность

Наконец, используя аналогичные методы, вы можете легко добавить некоторые эффекты параллакса или другие интерактивные эффекты на свой фон:

Многократные фоны полезны в таких сценариях, и хотя мы говорим только о фонах (не о контенте), их использование, безусловно, является хорошим способом избежать загрязнения HTML-кода сложными ненужными элементами. Но, как я уже сказал, есть некоторые штрафы, если вам нужно создать сложный и динамический фон: вы не можете получить доступ к отдельному слою по ID, классу или любому другому параметру. Вы должны помнить порядок слоев в вашем коде, и чтобы изменить атрибут только для одного слоя, вам нужно будет создать строку, описывающую этот атрибут для всех ваших слоев. Чтобы обновить один слой, вам нужно обновить всю композицию:

sea.style.backgroundPosition = "top " + fishY + "px right " + fishX + "px, " + mermaidX + "px bottom," + fishesX + "px " + fishesY + "px, top left";

Я уверен, что можно создать хорошую и полезную библиотеку JavaScript, которая виртуализирует все эти слои и обеспечит простой способ изменения атрибутов для отдельного слоя, сохраняя чистоту вашего HTML-кода и DOM.

Совместимость

Все современные браузеры, включая IE10 и 9, поддерживают несколько фонов. Вы также можете использовать некоторые инструменты, такие как Modernizr, чтобы обеспечить некоторый уровень совместимости для старых браузеров, например, предоставляя альтернативный фон. Как написал Крис Койер в своей статье о порядке наложения нескольких фонов , вы можете использовать следующий подход:

.multiplebgs body {
  /* Awesome multiple BG declarations that transcend reality and impress chicks */
}
.no-multiplebgs body {
  /* laaaaaame fallback */
}

Если вас не устраивает использование JavaScript для обеспечения обратной совместимости для новых правил CSS3, вы можете просто определить свойство background дважды (но этот подход может привести к ненужным загрузкам для современных браузеров, в зависимости от того, как они обрабатывают такие правила):

/* multiple bg fallback */
background: #000 url(...) ...;
/* Awesome multiple BG declarations that transcend reality and impress chicks */
background: url(...), url(...), url(...), #000 url(...);

И, наконец, если вы хотите это знать: да, вы можете использовать несколько фонов в своих приложениях в стиле Metro для Windows 8, созданных с использованием HTML и JavaScript.

PS Посмотрите эту феноменальную статью Алекса Уокера о принципе цикады.

Примечание.
Свойства CSS, обсуждаемые в этой статье, определены в модуле « Фоны и границы CSS3 », который в настоящее время находится в состоянии «Рабочий чертёж». Между тем, он кажется достаточно стабильным, но все еще может измениться в деталях.