今回は、Web制作でよく使用するパーツをjQueryを使わずに、JavaScriptで作ってみました。
参考サイト↓
ハンバーガーメニュー
HTML
/**html**/
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hamburger-js</title>
<link rel="stylesheet" href="https://unpkg.com/ress/dist/ress.min.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header class="header">
<button type="button" id="jsHam" class="button hamburger__btn" aria-controls="js-global-menu" aria-expanded="false" aria-label="メニューを開閉する">
<span class="hamburger__line"></span>
</button>
<div class="header__sp__menu" id="js-global-menu" aria-hidden="true">
<nav>
<ul>
<li><a href="#">menu01</a></li>
<li><a href="#">menu02</a></li>
<li><a href="#">menu03</a></li>
<li><a href="#">menu04</a></li>
<li><a href="#">menu05</a></li>
</ul>
</nav>
</div>
</header>
<script type="text/javascript" src="js/main.js"></script>
</body>
</html>
Scss
/**scss**/
.button {
display: inline-block;
text-decoration: none;
appearance: none;
border: none;
background-color: transparent;
cursor: pointer;
}
.header {
width: 100%;
height: 64px;
background-color: $color-bg;
.hamburger__btn {
position: fixed;
top: 8px;
right: 20px;
z-index: 3;
width: 48px;
height: 48px;
.hamburger__line {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
width: 40px;
height: 1px;
background-color: $color-main;
&::before,
&::after {
content: "";
display: block;
width: 100%;
height: 100%;
background-color: inherit;
position: absolute;
transition: transform .2s ease-in-out;
}
&::before {
top: -8px;
}
&::after {
bottom: -8px;
}
}
}
.hamburger__btn[aria-expanded="true"] {
.hamburger__line {
background-color: transparent;
&::before,
&::after {
top: 0;
background-color: $color-main;
transition: transform .3s ease-in-out;
}
&::before {
transform: rotate(45deg);
}
&::after {
transform: rotate(-45deg);
}
}
}
&__sp__menu {
position: fixed;
width: 100%;
height: 100vh;
top: 0;
left: 0;
background-color: $color-accent;
visibility: hidden;
&.visible {
visibility: visible;
animation: fade-in .3s ease-in-out;
}
}
}
@keyframes fade-in {
0% {
visibility: hidden;
opacity: 0;
}
50% {
visibility: visible;
opacity: 0.5;
}
100% {
visibility: visible;
opacity: 1;
}
}
JavaScript
/**javascript**/
const jsHamburger = document.getElementById('jsHam');
const body = document.body;
const spHeaderMenu = document.getElementById('js-global-menu');
jsHamburger.addEventListener('click', function(){
body.classList.toggle('js__drawerActive')
if(this.getAttribute('aria-expanded') == 'false') {
this.setAttribute('aria-expanded', 'true');
spHeaderMenu.classList.add('visible');
spHeaderMenu.getAttribute('aria-hidden', 'false');
} else {
this.setAttribute('aria-expanded', 'false');
spHeaderMenu.classList.remove('visible');
spHeaderMenu.getAttribute('aria-hidden', 'true');
}
});
ドロワーメニュー
HTML
/**html**/
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ドロワーメニュー|Javascript</title>
<link rel="stylesheet" href="https://unpkg.com/ress/dist/ress.min.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header class="header">
<button type="button" id="jsHam" class="button hamburger__btn" aria-controls="js-global-menu" aria-expanded="false" aria-label="メニューを開閉する">
<span class="hamburger__line"></span>
</button>
<div class="header__sp__menu" id="js-global-menu" area-hidden="true">
<nav>
<ul>
<li><a href="">menu01</a></li>
<li><a href="">menu02</a></li>
<li><a href="">menu03</a></li>
<li><a href="">menu04</a></li>
<li><a href="">menu05</a></li>
</ul>
</nav>
</div>
<div class="drawer__bg" id="js-drawer-bg"></div>
</header>
<script type="text/javascript" src="js/main.js"></script>
</body>
</html>
Scss
/**scss**/
@use '../setting/setting' as *;
.header {
background-color: $color-main;
height: 64px;
.button {
display: inline-block;
text-decoration: none;
border: none;
cursor: pointer;
background-color: transparent;
}
.hamburger__btn {
position: fixed;
top: 8px;
right: 24px;
z-index: 5;
width: 48px;
height: 48px;
background-color: transparent;
.hamburger__line {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
width: 80%;
height: 2px;
background-color: $color-black;
&::before,
&::after {
content: "";
background-color: inherit;
position: absolute;
display: block;
width: 100%;
height: 100%;
transition: transform .3s cubic-bezier(0,.26,.69,1);
}
&::before {
top: -8px;
}
&::after {
bottom: -8px;
}
}
}
&__sp__menu {
position: fixed;
top: 0;
right: 0;
bottom: 0;
z-index: 4;
width: 280px;
height: 100vh;
background-color: $color-black;
transform: translateX(280px);
overflow: hidden;
transition: transform .3s cubic-bezier(0,.26,.69,1);
a {
color: $color-white;
}
}
.drawer__bg {
position: fixed;
z-index: 3;
width: 100%;
height: 100vh;
top: 0;
right: 0;
left: 0;
bottom: 0;
margin: auto;
background-color: $color-black;
visibility: hidden;
opacity: 0;
}
}
.hamburger__btn[aria-expanded="true"] {
.hamburger__line {
background-color: transparent;
&::before,
&::after {
top: 0;
background-color: $color-white;
}
&::before {
transform: rotate(45deg);
}
&::after {
transform: rotate(-45deg);
}
}
}
.is-drawerActive {
.header__sp__menu {
transform: translateX(0);
transition: transform .4s cubic-bezier(.57,.03,.6,.7);
}
.drawer__bg {
visibility: visible;
opacity: 0.7;
transition: .3s;
}
}
JavaScript
/**js**/
const jsHamburger = document.getElementById('jsHam');
const body = document.body;
const spHeaderMenu = document.getElementById('js-global-menu');
const drawerBg = document.getElementById('js-drawer-bg');
jsHamburger.addEventListener('click', function(){
body.classList.toggle('is-drawerActive')
if(this.getAttribute('aria-expanded') == 'false') {
this.setAttribute('aria-expanded', 'true');
spHeaderMenu.setAttribute('area-hidden','false')
} else {
this.setAttribute('aria-expanded', 'false');
spHeaderMenu.setAttribute('area-hidden', 'true')
};
});
drawerBg.addEventListener('click', () => {
body.classList.remove('is-drawerActive')
jsHamburger.setAttribute('aria-expanded', 'false')
spHeaderMenu.setAttribute('area-hidden', 'true')
});
ローディング
HTML
/**html**/
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ローディング|js</title>
<link rel="stylesheet" href="https://unpkg.com/ress/dist/ress.min.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div id="loadingBox">
<div class="spinner-box">
<div class="pulse-container">
<div class="pulse-bubble pulse-bubble-1"></div>
<div class="pulse-bubble pulse-bubble-2"></div>
<div class="pulse-bubble pulse-bubble-3"></div>
</div>
</div>
</div>
<section class="contents">
<h1>main_content</h1>
</section>
<script type="text/javascript" src="js/main.js"></script>
</body>
</html>
Scss
/**scss**/
.contents {
width: 100%;
height: 100vh;
background-color: $color-main;
text-align: center;
h1 {
color: $color-black;
font-size: 2.4rem;
padding-top: 46vh;
}
}
#loadingBox {
width: 100%;
height: 100vh;
background-color: $loading-bg-color;
position: fixed;
top: 0;
left: 0;
z-index: 10;
.spinner-box {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
.pulse-container {
width: 120px;
display: flex;
align-items: center;
justify-content: space-between;
.pulse-bubble {
width: 18px;
height: 18px;
border-radius: 50%;
background-color: $loading-color;
&-1 {
animation: pulse .4s ease .0s infinite alternate;
}
&-2 {
animation: pulse .4s ease .2s infinite alternate;
}
&-3 {
animation: pulse .4s ease .4s infinite alternate;
}
}
}
}
}
.loadingNone {
animation: loadingAnime 1s 2s forwards;
}
@keyframes pulse {
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: .25;
transform: scale(.75);
}
}
@keyframes loadingAnime {
0% {
opacity: 1;
}
99% {
opacity: 0;
}
100% {
opacity: 0;
display: none;
}
}
JavaScript
/**javascript**/
const loadingBox = document.getElementById('loadingBox');
function loadingStop() {
loadingBox.classList.add('loadingNone');
}
window.addEventListener('load', loadingStop());
ページトップ
HTML
/**html**/
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ページトップ|js</title>
<link rel="stylesheet" href="https://unpkg.com/ress/dist/ress.min.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<h1>page-top</h1>
<div id="js-scroll-fadein" class="js-scroll-fadein arrow"></div>
<script type="text/javascript" src="js/main.js"></script>
</body>
</html>
Scss
/**Scss**/
h1 {
font-size: 3rem;
text-align: center;
color: $color-black;
}
.js-scroll-fadein {
transition: opacity 1s;
visibility: hidden;
opacity: 0;
&.js-fadein {
visibility: visible;
opacity: 1;
}
}
.arrow {
position: fixed;
right: 16px;
bottom: 24px;
cursor: pointer;
background-color: $color-bg;
box-shadow: 8px 8px 20px rgb(112 112 112 / 20%), -8px -8px 20px #fff;
width: 60px;
height: 60px;
border-radius: 50%;
&:hover {
box-shadow: 8px 8px 20px rgb(160 160 160 / 20%), -8px -8px 20px #fff, inset 4px 4px 10px rgb(160 160 160 / 20%), inset -4px -4px 10px #fff;
}
&::before {
content: "";
width: 24px;
height: 24px;
border-top: solid 3px $color-black;
border-right: solid 3px $color-black;
transform: rotate(-45deg);
position: absolute;
top: 10px;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
}
JavaScript
/**javascript**/
const topButton = document.getElementById('js-scroll-fadein');
function getScrolled() {
return( window.pageYOffset !== undefined) ? window.pageYOffset: document.documentElement.scrollTop;
}
window.onscroll = function() {
(getScrolled() > 500) ? topButton.classList.add('js-fadein'): topButton.classList.remove('js-fadein');
}
function scrollToTop(){
window.scrollTo({
top: 0,
behavior: 'smooth'
});
}
topButton.onclick = function(){
scrollToTop();
}
モーダルウィンドウ
HTML
/**html**/
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>モーダルウィンドウ|js</title>
<link rel="stylesheet" href="https://unpkg.com/ress/dist/ress.min.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<button id="openModal">OPEN MODAL</button>
<section id="modalArea" class="modalArea">
<div id="modalBg" class="modalBg"></div>
<div class="modalWrapper">
<div class="modalContents">
<p>テキスト□テキスト□テキスト□テキスト□テキスト□テキスト□テキスト□テキスト□テキスト□テキスト□テキスト□テキスト□テキスト□テキスト□テキスト□テキスト□</p>
</div>
<div id="closeModal" class="closeModal">×</div>
</div>
</section>
<script type="text/javascript" src="js/main.js"></script>
</body>
</html>
Scss
/**scss**/
.modalArea {
visibility: hidden;
opacity: 0;
position: fixed;
z-index: 10;
top: 0;
left: 0;
width: 100%;
height: 100%;
transition: .4s;
.modalBg {
width: 100%;
height: 100%;
background-color: $color-modal-bg;
}
.modalWrapper {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: 85%;
max-width: 800px;
padding: 45px;
background-color: $color-black;
.modalContents {
p {
font-size: 16px;
color: $color-white;
}
}
.closeModal {
position: absolute;
top: -11px;
right: 16px;
font-size: 3rem;
color: $color-white;
cursor: pointer;
}
}
&.is-show {
visibility: visible;
opacity: 1;
}
}
#openModal {
width: 250px;
height: 60px;
font-size: 1.6rem;
text-align: center;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
border: 2px solid $color-black;
background-color: $color-white;
color: $color-black;
&:hover {
background-color: $color-black;
color: $color-white;
}
}
JavaScript
/**javascript**/
const modalArea = document.getElementById('modalArea');
const openModal = document.getElementById('openModal');
const closeModal = document.getElementById('closeModal');
const modalBg = document.getElementById('modalBg');
const toggle = [openModal,closeModal,modalBg];
for(let i = 0; i < toggle.length; i++) {
toggle[i].addEventListener('click', function(){
modalArea.classList.toggle('is-show');
},false);
}
アコーディオン
HTML
/**html**/
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>アコーディオン|js</title>
<link rel="stylesheet" href="https://unpkg.com/ress/dist/ress.min.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<section class="accordion">
<div class="accordion__container">
<h4 class="accordion__ttl jsAccordionTitle">アコーディオン01</h4>
<div class="accordion__content">アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容</div>
<h4 class="accordion__ttl jsAccordionTitle">アコーディオン02</h4>
<div class="accordion__content">アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容</div>
<h4 class="accordion__ttl jsAccordionTitle">アコーディオン03</h4>
<div class="accordion__content">アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容</div>
<h4 class="accordion__ttl jsAccordionTitle">アコーディオン04</h4>
<div class="accordion__content">アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容アコーディオンの内容</div>
</div>
</section>
<script type="text/javascript" src="js/main.js"></script>
</body>
</html>
Scss
/**Scss**/
$color-black: #000;
$color-gray: rgb(255, 237, 98);
$color-white: #fff;
$color-active: rgb(227, 227, 227);
.accordion {
margin-top: 42px;
&__container {
width: 72%;
margin: 0 auto;
}
&__ttl {
background-color: $color-white;
border-top: 1px solid $color-black;
color: $color-black;
font-size: 18px;
padding: 12px 12px 12px 32px;
cursor: pointer;
position: relative;
&:last-of-type {
border-bottom: 1px solid $color-black;
}
&::before,
&::after {
content: "";
display: block;
background-color: $color-black;
position: absolute;
top: 50%;
width: 32px;
height: 2px;
right: 24px;
transform: translateY(-50%);
}
&::after {
transform: rotate(90deg);
transition-duration: .3s;
}
&:hover,
&:active,
&.is-active {
background-color: $color-active;
}
&.is-active {
&::before {
opacity: 0;
}
&::after {
transform: rotate(0);
}
}
}
&__content {
padding: 0 16px;
height: 0;
opacity: 0;
line-height: 0;
overflow: hidden;
transition-duration: .3s;
&.is-open {
background-color: $color-gray;
line-height: normal;
margin: 12px 0;
padding: 16px;
height: auto;
opacity: 1;
}
}
}
JavaScript
/**javascript**/
const ttl = document.querySelectorAll('.jsAccordionTitle');
ttl.forEach(ttlEach => {
let content = ttlEach.nextElementSibling;
ttlEach.addEventListener('click', () => {
ttlEach.classList.toggle('is-active');
content.classList.toggle('is-open');
})
});
タブ
HTML
/**html**/
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>タブ|js</title>
<link rel="stylesheet" href="https://unpkg.com/ress/dist/ress.min.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<section class="tab">
<ul class="tab__menu">
<li class="tab__menu__item">
<span class="tab__trigger js__tab__trigger is-active" data-id="tab-01">タブ01</span>
</li>
<li class="tab__menu__item">
<span class="tab__trigger js__tab__trigger" data-id="tab-02">タブ02</span>
</li>
<li class="tab__menu__item">
<span class="tab__trigger js__tab__trigger" data-id="tab-03">タブ03</span>
</li>
</ul>
<div class="tab__content">
<div class="tab__content__item js__tab__target is-active" id="tab-01">
<p>テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01テキスト01</p>
</div>
<div class="tab__content__item js__tab__target" id="tab-02">
<p>テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02テキスト02</p>
</div>
<div class="tab__content__item js__tab__target" id="tab-03">
<p>テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03テキスト03</p>
</div>
</div>
</section>
<script type="text/javascript" src="js/main.js"></script>
</body>
</html>
Scss
/**scss**/
$color-black: #000;
$color-white: #fff;
$color-accent: #c0e4ff;
$color-border: rgb(222, 222, 222);
$color-bg: #efefef;
a {
list-style: none;
text-decoration: none;
}
li {
list-style: none;
}
.tab {
width: 72%;
margin: 50px auto;
&__menu {
display: flex;
&__item {
&:nth-child(even) {
margin: 0 20px;
}
}
}
&__trigger {
cursor: pointer;
display: block;
padding: 8px 32px;
border: 1px solid $color-border;
border-bottom: 0;
border-radius: 3px 3px 0 0;
overflow: hidden;
background-color: $color-bg;
}
&__trigger.is-active {
background-color: $color-accent;
}
&__content {
border: 1px solid $color-border;
border-radius: 0 3px 3px 3px;
&__item {
padding: 24px;
box-sizing: border-box;
display: none;
}
&__item.is-active {
display: block;
animation: fade .5s ease-in-out;
}
}
}
@keyframes fade {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
JavaScript
/**javascript**/
document.addEventListener('DOMContentLoaded', () => {
const tabTrigger = document.querySelectorAll('.js__tab__trigger');
const tabTarget = document.querySelectorAll ('.js__tab__target');
tabTrigger.forEach(tabTriggers => {
tabTriggers.addEventListener('click', (e) => {
let currentMenu = e.currentTarget;
let currentContent = document.getElementById(currentMenu.dataset.id);
tabTrigger.forEach(tabTriggers => {
tabTriggers.classList.remove('is-active');
});
currentMenu.classList.add('is-active');
tabTarget.forEach(tabTargets => {
tabTargets.classList.remove('is-active');
});
if (currentContent !== null) {
currentContent.classList.add('is-active');
}
});
});
});