Парочка приемов работы с элементом iframe (туториал)

Доброго времени суток, друзья!

Элемент iframe (от англ. inline frame — встроенный фрейм) создаёт встроенный фрейм, который находится внутри обычного документа, он позволяет загружать в область заданных размеров любые другие независимые документы — WebReference

Спецификация.

Задача

Сделать одностраничник, состоящий из фреймов, наподобие Dashboard на Codepen.

Результат должен быть примерно следующим:

Возможное решение

Разметка одной секции может выглядеть так:

<section>     <h3>Title</h3>     <div class="viewport">         <iframe src="index.html" seamless scrolling="no"></iframe>     </div>     <div class="buttons">         <button onclick="window.open('index.html', '_blank')" title="fullscreen">demo</button>         <button onclick="document.location='code.7z'" title="download">code</button>     </div> </section> 


Что здесь интересного?

Поскольку каждый блок имеет заголовок, мы может обернуть его в section (согласно спецификации section и article должны иметь заголовки).

.viewport — блок, содержащий фрейм (далее мы будет называть его просто блоком).

Атрибут src ссылается на содержимое фрейма, которое заменено «кавером» с помощью JS (об этом далее).

Seamless определяет, что содержимое фрейма должно отображаться так, словно оно является частью документа (в настоящее время не поддерживается).

Scrolling=«no» запрещает отображение полос прокрутки во фрейме.

Window.open — один из способов открыть содержимое фрейма ("_blank" — в новой вкладке).

Document.location — один из способов скачать файл.

Весь HTML

<!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8">     <meta name="viewport" content="width: device-width">     <title>Iframe</title>     <link rel="stylesheet" href="style.css">     <script src="script.js" defer></script> </head> <body>     <header>         <h2>Title</h2>     </header>     <main>         <section>             <h3>Title</h3>             <div class="viewport">                 <iframe src="index.html" seamless scrolling="no"></iframe>             </div>             <div class="buttons">                 <button onclick="window.open('index.html', '_blank')" title="fullscreen">demo</button>                 <button onclick="document.location='code.7z'" title="download">code</button>             </div>         </section>                  <section>             <h3>Title</h3>             <div class="viewport">                 <iframe src="index.html" seamless scrolling="no"></iframe>             </div>             <div class="buttons">                 <button onclick="window.open('index.html', '_blank')" title="fullscreen">demo</button>                 <button onclick="document.location='code.7z'" title="download">code</button>             </div>         </section>                  <section>             <h3>Title</h3>             <div class="viewport">                 <iframe src="index.html" seamless scrolling="no"></iframe>             </div>             <div class="buttons">                 <button onclick="window.open('index.html', '_blank')" title="fullscreen">demo</button>                 <button onclick="document.location='code.7z'" title="download">code</button>             </div>         </section>                  <section>             <h3>Title</h3>             <div class="viewport">                 <iframe src="index.html" seamless scrolling="no"></iframe>             </div>             <div class="buttons">                 <button onclick="window.open('index.html', '_blank')" title="fullscreen">demo</button>                 <button onclick="document.location='code.7z'" title="download">code</button>             </div>         </section>     </main>     <footer>         <p>© All rights reserved.</p>     </footer> </body></html> 

Проблема № 1. Вписать фрейм в блок

По умолчанию размер iframe в Chrome составляет 304х154px.

Применим к section следующие стили:

section {     margin: 1em;     width: 300px;     background: rgba(0, 0, 0, 0.15);     border-radius: 5px;     box-shadow: inset 0 0 50px rgba(0, 0, 0, 0.3); } 

Установка ширины section в 300px (+meta name=«viewport» и display: flex у родительского элемента) обеспечивает одинаковое отображение фрейма на экранах с различным разрешением.

Получается так:

А должно быть так:

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

Одним из способов решения данной проблемы является масшабирование iframe:

/* для сохранения пропорций берем одно из "популярных" разрешений экрана, например, 1024х768px, уменьшаем масштаб фрейма до 25%, указываем координаты точки, относительно которой будет происходить трансформация - 0 0 (верхний левый угол) */ iframe {     width: 1024px;     height: 768px;     transform: scale(.25);     transform-origin: 0 0; } 

Далее определяем размеры блока. Ширина: 1024 * 0.25 = 256px, высота: 768 * 0.25 = 192px.

Весь CSS

@import url("https://fonts.googleapis.com/css?family=Playfair+Display|Roboto&display=swap");  * {     margin: 0;     padding: 0;     box-sizing: border-box; }  body {     min-height: 100vh;     background: radial-gradient(circle, skyblue, steelblue) fixed;     display: flex;     flex-direction: column;     font-family: "Playfair Display", serif;     text-align: center;     color: #222; }  h2 {     font-size: 2em;     text-transform: uppercase;     text-shadow: 1px 1px #ddd;     user-select: none; }  main {     flex-grow: 1;     display: inherit;     flex-wrap: wrap;     justify-content: space-evenly;     align-content: space-evenly; }  section {     margin: 1em;     width: 300px;     background: rgba(0, 0, 0, 0.15);     border-radius: 5px;     box-shadow: inset 0 0 50px rgba(0, 0, 0, 0.3); }  .viewport {     margin: auto;     width: 256px;     height: 192px;     overflow: hidden; }  iframe {     width: 1024px;     height: 768px;     transform: scale(.25);     transform-origin: 0 0; }  h3 {     padding: 0.5em 0;     font-size: 1em;     letter-spacing: 2px;     text-transform: uppercase;     text-align: center;     color: #ddd;     text-shadow: 1px 1px 0 #222;     user-select: none; }  button {     border: none;     outline: none;     margin: 0.75em 0;     padding: 0.75em;     width: 100px;     background: linear-gradient(to bottom, skyblue, steelblue);     font-family: inherit;     font-weight: bold;     letter-spacing: 2px;     color: inherit;     text-transform: uppercase;     border-radius: 10px;     box-shadow: 0 0 2px rgba(0, 0, 0, 0.4);     cursor: pointer;     transition: .2s; }  button + button {     margin-left: 1em; }  button:active, button:checked, button:focus, button:hover {     background: radial-gradient(steelblue, skyblue);     color: #ddd;     box-shadow: inset 0 0 2px rgba(0, 0, 0, .4); } 

Проблема № 2. Отображение содержимого при наведении курсора

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

Для того, чтобы решить данную проблему, мы отключаем содержимое фреймов и заменяем его картинкой. Картинка должна иметь размер 1024х768px. Если быть более точным, то мы меняем адреса файлов — значение src (на Codepen эта проблема решается с помощью короткой анимации содержимого фрейма). При наведении курсора на определенный фрейм должно отображаться его содержимое.

Решение может быть таким:

// находим все фреймы в документе let iframes = document.querySelectorAll("iframe")  // перебираем массив (на самом деле здесь мы имеем дело с объектом Nodelist, но это неважно) for (let i = 0; i < iframes.length; i++){     let iframe = iframes[i],          // сохраняем оригинальное значение srс     originalSrc = iframe.src          // заменяем содержимое фрейма картинкой     iframe.src = "cover.jpg"          // при наведении курсора отображаем содержимое фрейма     iframe.addEventListener("mouseover", () => iframe.src = originalSrc)          // возвращаем "кавер"     iframe.addEventListener("mouseout", () => iframe.src = "cover.jpg") } 

Результат:

Благодарю за внимание. Всех благ.

ссылка на оригинал статьи https://habr.com/ru/post/485304/

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *