HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
Any URLs added here will be added as <link>
s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
You can also link to another Pen here (use the .css
URL Extension) and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, use the appropriate URL Extension and we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
Any URL's added here will be added as <script>
s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
Search for and use JavaScript packages from npm here. By selecting a package, an import
statement will be added to the top of the JavaScript editor for this package.
Using packages here is powered by Skypack, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ES6 import
usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
<body>
<header class="header">
<div class="container header__wrap">
<nav class="header__menu header-menu">
<img class="header-menu__logo" src="./img/apple_logo_black.svg" alt="">
<ul class="header-menu__list">
<li class="header-menu__item"><a href="#present">О товаре</a></li>
<li class="header-menu__item"><a href="#card">Карточка товара</a></li>
<li class="header-menu__item"><a href="#characteristics">Характеристики</a></li>
<li class="header-menu__item"><a href="#cross-sell">Дополняют товар</a></li>
<li class="header-menu__item"><a href="#">Отзывы</a></li>
<li class="header-menu__item"><a href="#">Условия доставки</a></li>
</ul>
<div class="header-menu__burger"></div>
</nav>
</div>
</header>
<main>
<section class="present" id="present">
<div class="container">
<h1 class="present__title">iPhone12</h1>
<p class="present__description">A14 Bionic, самый быстрый процессор iPhone. Дисплей OLED от края до края. Передняя панель Ceramic Shield, которая в четыре раза снижает риск повреждений дисплея при падении. И Ночной режим на всех камерах. Всё это есть в iPhone 12</p>
<figure class="present__img">
<img src="./img/iPhone-main.png" alt="iPhone12">
</figure>
</div>
</section>
<section class="card" id="card">
<div class="container card__wrap">
<figure class="card__image">
<img class="card__image_item" src="./img/iPhone-graphite.png" alt="iPhone12">
</figure>
<div class="card-details">
<h2 class="card-details__title">Смартфон Apple iPhone 12 Pro 128GB Graphite</h2>
<ul class="card-detail__buttons">
<li class="card-details__wrap-btn">
<button class="card-detail__change active" type="button">Графитовый</button>
</li>
<li class="card-details__wrap-btn">
<button class="card-detail__change" type="button">Серебристый</button>
</li>
<li class="card-details__wrap-btn">
<button class="card-detail__change" type="button">Тихоокеанский синий</button>
</li>
</ul>
<div class="card-details__description">
<ul class="card-details__description-list description">
<li class="card-details__description-item description__screen">Экран 6.1"/2532x1170 Пикс</li>
<li class="card-details__description-item description__tech-screen">Технология экрана OLED</li>
<li class="card-details__description-item description__processor">Тип процессора A14 Bionic</li>
<li class="card-details__description-item description__memory">Встроенная память (ROM) 128 ГБ</li>
<li class="card-details__description-item description__camera">Основная камера МПикс 12/12/12/LiDAR</li>
</ul>
<a class="card-details__link-characteristics" href="#characteristics">Полные характеристики</a>
<div class="card-details__footer">
<p class="card-details__price">
99990₽
</p>
<button class="button button_buy card-details__button_buy" data-button-buy="Оплата">Купить</button>
<button class="button card-details__button_delivery" data-button-buy="Доставка и оплата">Купить с доставкой</button>
</div>
</div>
</div>
</div>
</section>
<section class="characteristics" id="characteristics">
<div class="container">
<h2 class="characteristics__main-title main-title">Характеристики</h2>
<ul class="characteristics__list">
<li class="characteristics__item">
<button class="characteristics__title active" type="button">Дисплей</button>
<div class="characteristics__description active">
<ul class="characteristics__list-description">
<li class="characteristics__item-description">
<p>Тип дисплея</p>
<p>Super Retina XDR (OLED)</p>
</li>
<li class="characteristics__item-description">
<p>Диагональ (дюйм)</p>
<p>6.1</p>
</li>
<li class="characteristics__item-description">
<p>Разрешение (пикс)</p>
<p>2532x1170</p>
</li>
<li class="characteristics__item-description">
<p>Плотность пикселей (PPI)</p>
<p>460</p>
</li>
<li class="characteristics__item-description">
<p>Количество цветов дисплея</p>
<p>16 млн.</p>
</li>
<li class="characteristics__item-description">
<p>Сенсорный дисплей </p>
<p>да</p>
</li>
<li class="characteristics__item-description">
<p>Тип сенсорного дисплея</p>
<p>емкостный</p>
</li>
<li class="characteristics__item-description">
<p>Поддержка Multitouch</p>
<p>да</p>
</li>
<li class="characteristics__item-description">
<p>Защита экрана</p>
<p>Ceramic Shield</p>
</li>
<li class="characteristics__item-description">
<p>Особенности дисплея</p>
<p>дисплей с расширенным цветовым охватом (P3), дисплей True Tone</p>
</li>
<li class="characteristics__item-description">
<p>Олеофобное покрытие</p>
<p>да</p>
</li>
</ul>
</div>
</li>
<li class="characteristics__item">
<button class="characteristics__title" type="button">Фотокамера</button>
<div class="characteristics__description">
<ul class="characteristics__list-description">
<li class="characteristics__item-description">
<p>Фотокамера (Мп)</p>
<p>12 + 12 + 12 + сканер LiDAR</p>
</li>
<li class="characteristics__item-description">
<p>Оптический зум</p>
<p>x4</p>
</li>
<li class="characteristics__item-description">
<p>Стабилизация изображения</p>
<p>оптическая</p>
</li>
<li class="characteristics__item-description">
<p>Автофокус</p>
<p>гибридный</p>
</li>
<li class="characteristics__item-description">
<p>Вспышка</p>
<p>True Tone</p>
</li>
<li class="characteristics__item-description">
<p>Видеозапись</p>
<p>да</p>
</li>
<li class="characteristics__item-description">
<p>Разрешение видеосъемки (пикс)</p>
<p>3840 x 2160</p>
</li>
<li class="characteristics__item-description">
<p>Частота кадров видеосъемки</p>
<p>60</p>
</li>
<li class="characteristics__item-description">
<p>Стабилизация видео</p>
<p>Да</p>
</li>
<li class="characteristics__item-description">
<p>Фронтальная камера (Мп)</p>
<p>12</p>
</li>
</ul>
</div>
</li>
<li class="characteristics__item">
<button class="characteristics__title" type="button">Связь</button>
<div class="characteristics__description">
<ul class="characteristics__list-description">
<li class="characteristics__item-description">
<p>Диапазоны GSM</p>
<p>850, 900, 1800, 1900</p>
</li>
<li class="characteristics__item-description">
<p>Диапазоны UMTS</p>
<p>850, 1700, 1900, 2100, 900</p>
</li>
<li class="characteristics__item-description">
<p>Интернет</p>
<p>GPRS, EDGE, 3G, 4G, 5G</p>
</li>
<li class="characteristics__item-description">
<p>Bluetooth</p>
<p>5.0</p>
</li>
<li class="characteristics__item-description">
<p>Wi-Fi (802.11)</p>
<p>b, g, n, ac, 2.4 ГГц, 5 ГГц</p>
</li>
<li class="characteristics__item-description">
<p>NFC</p>
<p>да</p>
</li>
<li class="characteristics__item-description">
<p>Разъем для синхронизации</p>
<p>Apple Lightning</p>
</li>
<li class="characteristics__item-description">
<p>Apple Pay</p>
<p>да</p>
</li>
</ul>
</div>
</li>
<li class="characteristics__item">
<button class="characteristics__title" type="button">Процессор</button>
<div class="characteristics__description">
<ul class="characteristics__list-description">
<li class="characteristics__item-description">
<p>Процессор</p>
<p>Apple A14 Bionic</p>
</li>
<li class="characteristics__item-description">
<p>64-битная архитектура</p>
<p>да</p>
</li>
</ul>
</div>
</li>
<li class="characteristics__item">
<button class="characteristics__title" type="button">Память</button>
<div class="characteristics__description">
<ul class="characteristics__list-description">
<li class="characteristics__item-description">
<p>Встроенная память (Гб)</p>
<p>128</p>
</li>
<li class="characteristics__item-description">
<p>Поддержка карт памяти</p>
<p>нет</p>
</li>
</ul>
</div>
</li>
<li class="characteristics__item">
<button class="characteristics__title" type="button">Мультимедиа</button>
<div class="characteristics__description">
<ul class="characteristics__list-description">
<li class="characteristics__item-description">
<p>Аудиоплеер</p>
<p>да</p>
</li>
<li class="characteristics__item-description">
<p>Видеоплеер</p>
<p>да</p>
</li>
<li class="characteristics__item-description">
<p>Аудиоразъем</p>
<p>Apple Lightning</p>
</li>
<li class="characteristics__item-description">
<p>Стереодинамики</p>
<p>Да</p>
</li>
</ul>
</div>
</li>
<li class="characteristics__item">
<button class="characteristics__title" type="button">Система</button>
<div class="characteristics__description">
<ul class="characteristics__list-description">
<li class="characteristics__item-description">
<p>Операционная система</p>
<p>iOS 14</p>
</li>
<li class="characteristics__item-description">
<p>Навигация</p>
<p>GPS, ГЛОНАСС, A-GPS, GALILEO, функция точного определения местоположения iBeacon, QZSS</p>
</li>
</ul>
</div>
</li>
<li class="characteristics__item">
<button class="characteristics__title" type="button">SIM-карта</button>
<div class="characteristics__description">
<ul class="characteristics__list-description">
<li class="characteristics__item-description">
<p>SIM-карта</p>
<p>nano-SIM</p>
</li>
<li class="characteristics__item-description">
<p>Кол-во SIM-карт</p>
<p>1</p>
</li>
</ul>
</div>
</li>
<li class="characteristics__item">
<button class="characteristics__title" type="button">Питание</button>
<div class="characteristics__description">
<ul class="characteristics__list-description">
<li class="characteristics__item-description">
<p>Тип аккумулятора</p>
<p>Литий-ионный, несъемный</p>
</li>
<li class="characteristics__item-description">
<p>Разъем для зарядки</p>
<p>Проприетарный Apple Lightning</p>
</li>
<li class="characteristics__item-description">
<p>Беспроводная зарядка</p>
<p>Да</p>
</li>
<li class="characteristics__item-description">
<p>Поддержка технологии быстрой зарядки</p>
<p>да</p>
</li>
<li class="characteristics__item-description">
<p>Воспроизведение музыки (ч)</p>
<p>65</p>
</li>
<li class="characteristics__item-description">
<p>Воспроизведение видео (ч)</p>
<p>17</p>
</li>
</ul>
</div>
</li>
<li class="characteristics__item">
<button class="characteristics__title" type="button">Корпус</button>
<div class="characteristics__description">
<ul class="characteristics__list-description">
<li class="characteristics__item-description">
<p>Тип корпуса</p>
<p>классический</p>
</li>
<li class="characteristics__item-description">
<p>Высота (мм)</p>
<p>146.7</p>
</li>
<li class="characteristics__item-description">
<p>Ширина (мм)</p>
<p>71.5</p>
</li>
<li class="characteristics__item-description">
<p>Толщина (мм)</p>
<p>7.4</p>
</li>
<li class="characteristics__item-description">
<p>Вес (г)</p>
<p>187</p>
</li>
<li class="characteristics__item-description">
<p>Материал корпуса</p>
<p>нерж. сталь, стекло</p>
</li>
<li class="characteristics__item-description">
<p>Защита от влаги и пыли</p>
<p>Да</p>
</li>
<li class="characteristics__item-description">
<p>Стандарт защиты</p>
<p>IP68</p>
</li>
</ul>
</div>
</li>
</ul>
</div>
</section>
<section class="cross-sell" id="cross-sell">
<div class="container">
<h2 class="cross-sell__main-title main-title">Дополняют этот товар</h2>
<ul class="cross-sell__list">
<!-- <li>
<article class="cross-sell__item">
<img class="cross-sell__image" src="cross-sell-dbase/img/50126638b.jpg" alt="">
<h3 class="cross-sell__title">Наушники Apple AirPods w/Charging Case</h3>
<p class="cross-sell__price">12990₽</p>
<button type="button" class="button button_buy cross-sell__button">Купить</button>
</article>
</li> -->
</ul>
<button class="button cross-sell__add">Показать ещё</button>
</div>
</section>
</main>
<div class="modal">
<div class="modal__block">
<button class="modal__close">✘</button>
<h2 class="modal__subtitle">Доставка и оплата</h2>
<form action="">
<input
class="modal__title-submit"
type="hidden"
name="name-good"
value="Смартфон Apple iPhone 12 Pro 128GB Graphite"
>
<h3 class="modal__title">Смартфон Apple iPhone 12 Pro 128GB Graphite</h3>
<label class="modal__label">
<span class="modal__label-text">Куда доставить</span>
<input class="modal__input" type="text">
</label>
<label class="modal__label">
<span class="modal__label-text">Кому</span>
<input class="modal__input" type="text">
</label>
<label class="modal__label">
<span class="modal__label-text">Телефон</span>
<input class="modal__input" type="text">
</label>
<button type="submit" class="button button_buy modal__submit">Заказать доставку</button>
</form>
</div>
</div>
html {
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
body {
min-width: 320px;
margin: 0;
background-color: #fff; /* под проект */
font-family: "San Francisco", Arial, sans-serif; /* в "" свой шрифт под проект*/
font-size: 16px;
font-weight: 400;
color: black;
line-height: 1;
}
button, input {
font: inherit;
}
button {
cursor: pointer;
}
img {
max-width: 100%;
height: auto;
}
a {
text-decoration: none;
color: inherit;
}
ul {
list-style: none;
}
h1, h2, h3, p, ul {
padding: 0;
margin: 0;
}
.button {
background-color: transparent;
border: 1px solid black;
border-radius: 15px;
padding: 8px 20px;
font-weight: bold;
font-size: 18px;
line-height: 32px;
}
.button_buy {
background-color: #FE3B3B;
border: 1px solid #FE3B3B;
color: #FFFFFF;
}
.main-title {
font-weight: 700;
font-size: 24px;
margin-bottom: 40px;
}
.container {
max-width: 950px;
margin: 0 auto;
padding: 30px 15px;
}
.visually-hidden {
position: absolute !important;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
padding: 0 !important;
border: 0 !important;
height: 1px !important;
width: 1px !important;
overflow: hidden;
}
/* при работе с float */
.clearfix::after {
content: "";
display: table;
clear: both;
}
/*header*/
.header__wrap {
max-width: 1130px;
}
.header-menu {
display: flex;
align-items: center;
}
.header-menu__logo {
max-width: 34px;
margin-right: auto;
}
.header-menu__list {
display: flex;
align-items: center;
}
.header-menu__item {
margin-right: 30px;
white-space: nowrap;
}
.header-menu__burger {
margin-left: auto;
}
@media (max-width: 375px) {
.logo {
margin-right: 10px;
}
}
/* present */
.present {
text-align: center;
padding-bottom: 90px;
padding-top: 30px;
}
.present__title {
font-size: 72px;
margin-bottom: 40px;
}
.present__description {
font-size: 36px;
line-height: 43px;
max-width: 865px;
margin: 0 auto 100px;
}
.present__img {
max-width: 440px;
margin: 0 auto;
}
@media (max-width: 968px) {
.present {
padding-bottom: 50px;
}
.present__title {
font-size: 54px;
margin-bottom: 30px;
}
.present__description {
font-size: 28px;
line-height: 32px;
max-width: 670px;
}
.present__img {
max-width: 380px;
}
}
@media (max-width: 698px) {
.present__title {
font-size: 48px;
}
.present__description {
font-size: 24px;
line-height: 28px;
max-width: 570px;
margin-bottom: 20px;
}
.present__img {
max-width: 300px;
}
}
@media (max-width: 520px) {
.present__title {
font-size: 38px;
}
.present__description {
font-size: 18px;
line-height: 24px;
max-width: 304px;
}
.present__img {
max-width: 280px;
}
}
.card {
padding-top: 90px;
}
.card__wrap {
display: flex;
align-items: center;
}
.card__image {
max-width: 300px;
margin: 0 70px 0 0;
}
.card-details__title {
font-size: 36px;
line-height: 43px;
}
.card-details__wrap-btn:not(:last-child) {
margin-right: 24px;
}
.card-detail__buttons {
display: flex;
font-size: 18px;
font-weight: 600;
margin-bottom: 40px;
white-space: nowrap;
}
.card-detail__change {
border: 1px solid transparent;
background-color: transparent;
padding: 11px 16px;
}
.card-detail__change.active {
color: #FE3B3B;
border-bottom: 1px solid #FE3B3B;
}
.card-details__description {
font-weight: 300;
font-size: 18px;
line-height: 21px;
margin-bottom: 20px;
}
.card-details__description-list {
margin-bottom: 18px;
}
.card-details__footer {
display: flex;
align-items: center;
}
.card-details__price {
min-width: 120px;
font-weight: 700;
font-size: 24px;
margin-right: 60px;
}
.card-details__link-characteristics {
display: block;
color: #4F80FF;
font-size: 18px;
line-height: 21px;
margin-bottom: 60px;
}
.card-details__button_buy {
margin-right: 28px;
}
@media (max-width: 968px) {
.card{
padding-top: 50px;
}
.card__wrap {
flex-direction: column;
}
.card__image {
order: 1;
margin-right: 0;
}
.card-details {
max-width: 600px;
margin-bottom: 30px;
}
}
@media (max-width: 698px) {
.card-details {
max-width: 400px;
margin-bottom: 20px;
}
.card-details__title {
text-align: center;
font-size: 28px;
margin-bottom: 30px;
}
.card-detail__buttons {
flex-direction: column;
align-items: center;
}
.card-details__wrap-btn:not(:last-child) {
margin-right: 0;
margin-bottom: 15px;
}
.card-details__footer {
flex-wrap: wrap;
align-items: start;
}
.card-details__price {
width: 100%;
margin-right: 0;
margin-bottom: 30px;
}
.card-details__button_buy {
margin-bottom: 30px;
}
}
.characteristics__list {
max-width: 920px;
}
.characteristics__item {
margin-bottom: 15px;
}
.characteristics__title {
position: relative;
width: 100%;
padding: 12px 30px;
background-color: transparent;
text-align: left;
}
.characteristics__title:after {
content: '';
position: absolute;
right: 15px;
bottom: 15px;
width: 17px;
height: 17px;
border: 1px solid;
border-color: transparent #000 #000 transparent;
transform: rotate(45deg);
transition: border-color 0.5s ease-in-out, bottom 0.5s ease-in-out;
}
.characteristics__title.active:after {
border-color: #000 transparent transparent #000;
bottom: 5px;
}
.characteristics__description {
margin-top: -2px;
border: 1px solid;
border-color: transparent #000 #000 #000;
height: 0;
overflow: hidden;
transition: height 0.5s ease-in-out;
}
.characteristics__title:focus {
outline:none;
}
.characteristics__description.active {
height: auto;
}
.characteristics__item-description {
display: flex;
align-items: center;
justify-content: space-between;
}
.characteristics__item-description {
padding: 15px 0;
}
.characteristics__item-description p {
margin: 0 15px;
}
.characteristics__item-description p:last-child {
text-align: right;
}
.characteristics__item-description:first-child {
padding-top: 30px;
}
.characteristics__item-description:last-child {
padding-bottom: 30px;
}
.cross-sell__list {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.cross-sell__item {
display: flex;
flex-direction: column;
max-width: 200px;
min-height: 380px;
margin-bottom: 60px;
box-shadow: 0 0 10px -1px rgba(221, 221, 221, 1);
}
.cross-sell__image {
box-shadow: 0 2px 6px 1px rgba(0, 0, 0, 0.1);
margin-bottom: 12px;
}
.cross-sell__inner-wrapper {
padding-right: 10px;
padding-left: 10px;
}
.cross-sell__title {
font-weight: 400;
font-size: 14px;
line-height: 17px;
margin-bottom: 10px;
}
.cross-sell__price {
font-weight: 700;
font-size: 24px;
margin-bottom: 10px;
}
.cross-sell__button {
margin-top: auto;
margin-bottom: 20px;
text-align: center;
max-width: 104px;
font-weight: 700;
font-size: 18px;
line-height: 32px;
}
@media (max-width: 968px) {
.cross-sell__list {
max-width: 560px;
justify-content: center;
margin: 0 auto;
}
.cross-sell__item {
margin: 0 30px 40px;
}
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
justify-content: center;
align-items: center;
background-color: rgba(0,0,0,0.4);
}
.modal.open {
display: flex;
}
.modal__block {
position: relative;
max-width: 640px;
padding: 20px;
background-color: #fff;
box-shadow: 0 2px 6px 1px rgba(0, 0, 0, 0.1);
}
.modal__subtitle {
font-size: 14px;
margin-bottom: 14px;
}
.modal__title {
font-size: 36px;
line-height: 43px;
margin-bottom: 30px;
}
.modal__close {
position: absolute;
right: 20px;
top: 20px;
background-color: transparent;
border: none;
font-size: 20px;
}
.modal__label {
display: flex;
margin-bottom: 12px;
align-items: center;
}
.modal__label-text {
min-width: 105px;
font-size: 14px;
margin-right: 20px;
}
.modal__input {
flex-grow: 1;
border-style: solid;
border-width: 1px;
border-color: transparent transparent #000 transparent ;
}
.modal__submit {
margin-top: 20px;
}
.cross-sell__add {
display: block;
margin-right: auto;
margin-left: auto;
}
document.addEventListener('DOMContentLoaded', () => {
'use strict';
// Функция получает товары с сервера.
const getData = (url, callback) => {
const request = new XMLHttpRequest()
request.open('GET', url)
request.send()
request.addEventListener('readystatechange', () => {
if (request.readyState !== 4) {
return
}
if (request.status === 200) {
const response = JSON.parse(request.response)
callback(response);
}
else {
console.error(new Error('Ошибка: ' + request.status))
}
})
}
// Функция для работы табов.
const tabs = () => {
// Кнопки переключения табов.
const cardDetailChangeElems = document
.querySelectorAll('.card-detail__change')
// Заголовок выбранного таба.
const cardDetailsTitleElem = document
.querySelector('.card-details__title')
// Картинка товара выбранного таба.
const cardImageItemElem = document.querySelector('.card__image_item')
// Цена товара выбранного таба.
const cardDetailsPriceElem = document
.querySelector('.card-details__price')
// Встроенная память (ROM) товара в выбранном табе.
const descriptionMemoryElem = document
.querySelector('.description__memory')
// Данные всех телефонов, которые есть в наличии.
const data = [
{
name: 'Смартфон Apple iPhone 12 Pro 128GB Graphite',
img: './img/iPhone-graphite.png',
price: 95990,
memoryROM: 128,
},
{
name: 'Смартфон Apple iPhone 12 Pro 256GB Silver',
img: './img/iPhone-silver.png',
price: 120000,
memoryROM: 256,
},
{
name: 'Смартфон Apple iPhone 12 Pro 128GB Pacific Blue',
img: './img/iPhone-blue.png',
price: 99990,
memoryROM: 128,
},
]
// Функция убирает выделение со всех кнопок переключения табов.
const deactive = () => {
// Пройти по всем кнопкам переключения табов.
// Убрать выделение с выбранной кнопки переключения таба.
cardDetailChangeElems.forEach(btn => btn.classList.remove('active'))
}
// Пройти по всем кнопкам переключения табов.
cardDetailChangeElems.forEach((btn, i) => {
btn.addEventListener('click', () => {
// Если кнопка переключения таба НЕ активная:
if (!btn.classList.contains('active')) {
deactive()
// Выделить кнопку переключения таба.
btn.classList.add('active')
// Изменить содержимое элементов таба.
cardDetailsTitleElem.textContent = data[i].name
cardImageItemElem.src = data[i].img
cardImageItemElem.alt = data[i].name
cardDetailsPriceElem.textContent = `${data[i].price}₽`
descriptionMemoryElem.textContent =
`Встроенная память (ROM) ${data[i].memoryROM} ГБ`
}
})
})
}
// Функция для работы аккордеона.
const accordion = () => {
// Блок с аккордеоном.
const characteristicsListElem = document
.querySelector('.characteristics__list')
// Все элементы аккордеона.
const characteristicsItemElems = characteristicsListElem
.querySelectorAll('.characteristics__item')
/*
Определение высоты блока с описанием части товара
активного элемента аккордеона.
*/
// Пройти по всем элементам аккордеона.
characteristicsItemElems.forEach(elem => {
if (elem.children[1].classList.contains('active')) {
elem.children[1].style
.height = `${elem.children[1].scrollHeight}px`
}
})
/*
Функция открывает пункт аккордеона. Принимает кнопку, на которую
нажали, и блок с характеристиками, которые нужно отобразить.
*/
const open = (button, dropDown) => {
// Закрыть все элементы аккордеона, кроме активного.
closeAllDrops(button, dropDown)
dropDown.style.height = `${dropDown.scrollHeight}px`
button.classList.add('active')
dropDown.classList.add('active')
}
/*
Функция закрывает пункт аккордеона. Принимает кнопку, на которую
нажали, и блок с характеристиками, которые нужно скрыть.
*/
const close = (button, dropDown) => {
button.classList.remove('active')
dropDown.classList.remove('active')
dropDown.style.height = '0'
}
// Функция закрывает все элементы аккордеона, кроме принятых.
const closeAllDrops = (button, dropDown) => {
// Пройти по всем элементам аккордеона.
characteristicsItemElems.forEach(elem => {
if (elem.children[0] !== button &&
elem.children[1] !== dropDown) {
close(elem.children[0], elem.children[1])
}
})
}
characteristicsListElem.addEventListener('click', event => {
const target = event.target
// Если кликнули по кнопке-заголовку аккордеона:
if (target.classList.contains('characteristics__title')) {
const parent = target.closest('.characteristics__item')
const description = parent
.querySelector('.characteristics__description')
// Если элемент аккордеона развёрнут:
if (description.classList.contains('active')) {
// Свернуть элемент аккордеона.
close(target, description)
}
// Если элемент аккордеона свёрнут:
else {
// Развернуть элемент аккордеона.
open(target, description)
}
}
})
// Обработчик клика по странице вне аккордеона.
document.body.addEventListener('click', event => {
const target = event.target
// Если кликнули вне аккордеона:
if (!target.closest('.characteristics__list')) {
// Закрыть все элементы аккордеона.
closeAllDrops()
}
})
/* ----------------------------------------------------------------- */
// Код работы аккордеона без делегирования.
// // Кнопка раскрытия/закрытия характеристик части товара.
// const characteristicsTitle = document
// .querySelectorAll('.characteristics__title')
// // Блок с характеристиками части товара.
// const characteristicsDescription = document
// .querySelectorAll('.characteristics__description')
// // Пройти по всем кнопкам раскрытия/закрытия характеристик части товара.
// characteristicsTitle.forEach((elem, i) => {
// elem.addEventListener('click', () => {
// /*
// Изменить вид кнопки раскрытия/закрытия характеристик части
// товара "раскрытая/закрытая".
// */
// elem.classList.toggle('active')
// // Скрыть/отобразить блок с характеристиками части товара.
// characteristicsDescription[i].classList.toggle('active')
// })
// })
}
// Функция работы модального окна.
const modal = () => {
// Кнопка "Купить".
const cardDetailsButtonBuy = document
.querySelector('.card-details__button_buy')
// Кнопка "Купить с доставкой".
const cardDetailsButtonDelivery = document
.querySelector('.card-details__button_delivery')
// Контейнер для дополнительных товаров.
const crossSellList = document.querySelector('.cross-sell__list')
// Модальное окно.
const modal = document.querySelector('.modal')
// Заголовок таба.
const cardDetailsTitle = document.querySelector('.card-details__title')
// Заголовок товара в модальном окне.
const modalTitle = modal.querySelector('.modal__title')
// Заголовок модального окна (для чего окно).
const modalSubtitle = modal.querySelector('.modal__subtitle')
// Скрытый инпут формы в модальном окне с названием товара.
const modalTitleSubmit = modal.querySelectorAll('.modal__title-submit')
// Функция открытия модального окна.
const openModal = event => {
// Кнопка, на которую нажали.
const target = event.target
modal.classList.add('open')
// Повесить на страницу обработчик нажатия клавиши "Escape".
document.addEventListener('keydown', escapeHandler)
modalTitle.textContent = cardDetailsTitle.textContent
modalTitleSubmit.value = cardDetailsTitle.textContent
modalSubtitle.textContent = target.dataset.buttonBuy
}
// Функция закрытия модального окна.
const closeModal = () => {
modal.classList.remove('open')
document.removeEventListener('keydown', escapeHandler)
}
// Функция-обработчик нажатия клавиши "Escape".
const escapeHandler = event => {
// Если нажали на клавишу "Escape":
if (event.code === 'Escape') {
closeModal()
}
}
// Закрытие модального окна.
// Повесить на модальное окно обработчик клика.
modal.addEventListener('click', event => {
const target = event.target
/*
Если кликнули по кнопке закрытия модального окна или
по оверлею вокруг модального окна:
*/
if (target.classList.contains('modal__close') || target === modal) {
closeModal()
}
})
// Повесить обработчик клика на кнопку "Купить".
cardDetailsButtonBuy.addEventListener('click', openModal)
// Повесить обработчик клика на кнопку "Купить с доставкой".
cardDetailsButtonDelivery.addEventListener('click', openModal)
crossSellList.addEventListener('click', event => {
const target = event.target
// Если кликнули по кнопке "Купить" карточки дополнительного товара.
if (target.classList.contains('button_buy')) {
const parent = target.closest('.cross-sell__item')
const cardTitle = parent.querySelector('.cross-sell__title')
modal.classList.add('open')
// Повесить на страницу обработчик нажатия клавиши "Escape".
document.addEventListener('keydown', escapeHandler)
modalTitle.textContent = cardTitle.textContent
modalTitleSubmit.value = cardTitle.textContent
modalSubtitle.textContent = target.dataset.buttonBuy
}
})
}
// Функция отображает дополнительные товары на странице.
const renderCrossSell = () => {
// Количество дополнительных товаров, отображаемых за один раз.
const COUNT_ROW_GOODS = 4
// Количество всех дополнительных товаров.
let countAllGoods = 0
// Контейнер для дополнительных товаров.
const crossSellList = document.querySelector('.cross-sell__list')
// Кнопка показа дополнительных товаров "Показать ещё".
const crossSellAdd = document.querySelector('.cross-sell__add')
// Все дополнительные товары.
const allGoods = []
// Функция добавления на страницу дополнительных товаров.
let wrapRender = null
// Функция переставляет элементы массива в случайном порядке.
const shuffle = arr => arr.sort(() => Math.random() - 0.5)
// Функция принимает объект с данными товара и создаёт карточку товара.
const createCrossSellItem = ({ photo: picture, name, price }) => {
const liItem = document.createElement('li')
liItem.innerHTML = `
<article class="cross-sell__item">
<img class="cross-sell__image" src=${picture} alt="${name}">
<div class="cross-sell__inner-wrapper">
<h3 class="cross-sell__title">${name}</h3>
<p class="cross-sell__price">${price}₽</p>
<button type="button" class="button button_buy cross-sell__button" data-button-buy="Оплата">Купить</button>
</div>
</article>
`
return liItem
}
/*
Функция добавляет на страницу дополнительные товары.
*/
const render = arr => {
arr.forEach(item => {
crossSellList.append(createCrossSellItem(item))
})
}
/*
Функция-обёртка принимает оборачиваемую функцию и количество её
допустимых запусков. Позволяет запустить переданную функцию
НЕ более переданного количества раз.
*/
const wrapper = (fn, count) => {
let counter = 0
return (...args) => {
/*
Если счётчик равен количеству допустимых запусков,
ничего не делать.
*/
if (counter === count) {
return
}
counter++
return fn(...args)
}
}
// Функция заполняет товарами контейнер для дополнительных товаров.
const createCrossSellList = goods => {
countAllGoods = goods.length
/*
Функция добавления на страницу дополнительных товаров.
Принимает функцию добавления товаров и количество отрисовок, необходимых для отображения на странице всех
дополнительных товаров по количеству,
отображаемому за одну отрисовку.
*/
wrapRender = wrapper(render,
Math.ceil(goods.length/COUNT_ROW_GOODS))
// Все дополнительные товары, перемешанные в случайном порядке.
allGoods.push(...shuffle(goods))
// Вырезать 4 первых товара из всех дополнительных.
const fourItems = allGoods.splice(0, COUNT_ROW_GOODS)
render(fourItems)
}
/*
Повесить обработчик клика по кнопке показа
дополнительных товаров "Показать ещё".
*/
crossSellAdd.addEventListener('click', () => {
wrapRender(allGoods.splice(0, COUNT_ROW_GOODS))
// Если отрисованы все карточки дополнительных товаров:
if (crossSellList.querySelectorAll('.cross-sell__item')
.length === countAllGoods) {
// Удалить кнопку отображения всех дополнительных товаров.
crossSellAdd.remove()
}
})
getData('./cross-sell-dbase/dbase.json', createCrossSellList)
}
tabs()
accordion()
modal()
renderCrossSell()
// Запуск работы адаптивного меню.
amenu('.header__menu', '.header-menu__list',
'.header-menu__item', '.header-menu__burger')
})
Also see: Tab Triggers