Элемент 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 — один из способов скачать файл.
<!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.
@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/