responsive html の template - end0tknr's kipple - web写経開発
上記entryの改訂版で、githubにも commitしています。
https://end0tknr.github.io/sandbox/responsive/
目次
html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>end0tknr</title> <!-- hamburger menu や 検索icon の為、google material icons 使用 --> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"> <link rel="stylesheet" href="css/common.css"> </head> <body> <header> <div class="site_logo"> <a href=""> <img src="img/site_logo.svg"/>end0tknr </a> </div> <div id="pc_menu"> <nav> <ul> <li><a href="#">メニュー 1</a></li> <li><a href="#">メニュー 2</a></li> <li><a href="#">メニュー 3</a></li> <li><a href="#">メニュー 4</a></li> <li><a href="#">メニュー 5</a></li> <li><a href="#">メニュー 6</a></li> <li> <a href="#"> <span class="material-icons">search</span> </a> </li> </ul> </nav> </div><!--#pc_menu--> <div id="sp_menu_open_container"> <span class="material-icons" id="sp_menu_open">menu</span> </div> <div id="sp_menu_overlay"> <span class="material-icons" id="sp_menu_close">close</span> <nav><!-- #pc_menu の内容を jsで copy します --> </nav> </div> </header> <section class="carousel"> <div> <ul> <li><img src="img/pic1.png"></li> <li><img src="img/pic2.png"></li> <li><img src="img/pic3.png"></li> <li><img src="img/pic4.png"></li> </ul> <button class="carousel_prev">«</button> <button class="carousel_next">»</button> </div> <nav></nav> </section><!--.carousel--> <section class="carousel"> <div> <ul> <li><img src="img/pic1.png"></li> <li><img src="img/pic2.png"></li> <li><img src="img/pic3.png"></li> <li><img src="img/pic4.png"></li> </ul> <button class="carousel_prev">«</button> <button class="carousel_next">»</button> </div> <nav></nav> </section><!--.carousel--> <section class="body"> <div class="image">image</div> <div class="text">text</div> </section> <div class="tab_menu"> <ul> <li><a href="#" data-id="" class="active">サイトの概要</a></li> <li><a href="#" data-id="">サービス内容</a></li> <li><a href="#" data-id="">お問い合わせ</a></li> </ul> <section class="active"> サイトの概要。サイトの概要。サイトの概要。サイトの概要。サイトの概要。サイトの概要。 サイトの概要。サイトの概要。サイトの概要。サイトの概要。サイトの概要。サイトの概要。 </section> <section> サービス内容。サービス内容。サービス内容。サービス内容。サービス内容。サービス内容。 サービス内容。サービス内容。サービス内容。サービス内容。サービス内容。サービス内容。 </section> <section> お問い合わせ。お問い合わせ。お問い合わせ。お問い合わせ。お問い合わせ。お問い合わせ。 お問い合わせ。お問い合わせ。お問い合わせ。お問い合わせ。お問い合わせ。お問い合わせ。 </section> </div><!-- .tab_menu --> <div class="tab_menu"> <ul> <li><a href="#" data-id="" class="active">サイトの概要</a></li> <li><a href="#" data-id="">サービス内容</a></li> <li><a href="#" data-id="">お問い合わせ</a></li> </ul> <section class="active"> サイトの概要。サイトの概要。サイトの概要。サイトの概要。サイトの概要。サイトの概要。 サイトの概要。サイトの概要。サイトの概要。サイトの概要。サイトの概要。サイトの概要。 </section> <section> サービス内容。サービス内容。サービス内容。サービス内容。サービス内容。サービス内容。 サービス内容。サービス内容。サービス内容。サービス内容。サービス内容。サービス内容。 </section> <section> お問い合わせ。お問い合わせ。お問い合わせ。お問い合わせ。お問い合わせ。お問い合わせ。 お問い合わせ。お問い合わせ。お問い合わせ。お問い合わせ。お問い合わせ。お問い合わせ。 </section> </div><!-- .tab_menu --> <script src="js/common.js"></script> </body> </html>
css
body { margin: 0; font-family: sans-serif; /* TODO font指定 */ } header { display: flex; padding: 0 16px; } .site_logo img { vertical-align: middle; margin-right: 10px; } .site_logo a { margin: 0; line-height: 64px; font-size: 32px; font-weight: bold; color: #000; text-decoration: none; white-space: nowrap; } #sp_menu_open_container { margin-left: auto; } #sp_menu_open_container #open { font-size: 32px; line-height: 64px; cursor: pointer; } #sp_menu_open_container #open.hide { display: none; } #sp_menu_overlay { position: fixed; top: 0; bottom: 0; right: 0; left: 0; background: rgba(255, 255, 255, 0.95); text-align: center; padding: 64px; opacity: 0; pointer-events: none; /* click無効化 */ transition: opacity .6s; z-index: 100; } #sp_menu_overlay.show { opacity: 1; pointer-events: auto; } #sp_menu_overlay #close { position: absolute; top: 16px; right: 16px; font-size: 32px; cursor: pointer; } #sp_menu_overlay ul { list-style-type: none; margin: 0; padding: 0; } #sp_menu_overlay li { margin-top: 24px; opacity: 0; transform: translateY(16px); transition: opacity .3s, transform .3s; } #sp_menu_overlay.show li { opacity: 1; transform: none; } #pc_menu { display: none; } .body .image { background: pink; height: 100px; } .body .text { background: silver; height: 100px; } .carousel { width: 80%; margin: 16px auto; } .carousel div { width: 100%; height: 220px; overflow: hidden; position: relative; } .carousel ul { list-style: none; margin: 0; padding: 0; height: 100%; display: flex; transition: transform .3s; } .carousel li { height: 100%; min-width: 100%; } .carousel li img { width: 100%; height: 100%; object-fit: cover; } .carousel_prev, .carousel_next { position: absolute; top: 50%; transform: translateY(-50%); border: none; background: rgba(0, 0, 0, .8); color: #fff; font-size: 24px; padding: 0 8px 4px; cursor: pointer; } .carousel_prev:hover, .carousel_next:hover { opacity: .8; } .carousel_prev { left: 0; } .carousel_next { right: 0; } .hidden { display: none; } .carousel nav { margin-top: 16px; text-align: center; } .carousel nav button + button { margin-left: 8px; } .carousel nav button { border: none; width: 16px; height: 16px; background: #ddd; border-radius: 50%; cursor: pointer; } .carousel nav .current { background: #999; } .tab_menu { margin: 30px auto; width: 500px; } .tab_menu ul { list-style: none; padding: 0; margin: 0; display: flex; } .tab_menu ul li a { display: inline-block; width: 100px; text-align: center; padding: 8px 0; color: #333; text-decoration: none; border-radius: 4px 4px 0 0; } .tab_menu ul li a.active { background: #333; color: #fff; } .tab_menu ul li a:not(.active):hover { opacity: 0.5; transition: opacity 0.4s; } .tab_menu section.active { background: #333; color: #fff; min-height: 150px; padding: 12px; display: block; } .tab_menu section { display: none; } .body .image { background: pink; height: 100px; } .body .text { background: silver; height: 100px; } @media (min-width: 600px) { #pc_menu { display: block; margin-left: auto; } #pc_menu ul { list-style-type: none; margin: 0; padding: 0; display: flex; } #pc_menu span { line-height: 64px; } #pc_menu a { display: block; line-height: 64px; margin-right: 20px; color: #000; text-decoration: none; white-space: nowrap; } #pc_menu a:hover { background: #f2f2f2; } #sp_menu_open_container { display: none; } section.body { display: flex; } .image { width: 200px; } .text { flex: 1; } } @media (min-width: 980px) { header { width: 980px; margin: 0 auto; } }
javascript
'use strict'; { var WindowBase = function() {}; WindowBase.prototype = { init_window: function(){ this.init_sp_menu(); var tab_menus = document.querySelectorAll('.tab_menu'); tab_menus.forEach(tab_menu=>{ this.init_tab_menu( tab_menu ); }); var carousels = document.querySelectorAll('.carousel'); carousels.forEach(carousel=>{ this.init_carousel( carousel ); this.update_carousel_buttons( carousel ); }); // カルーセルのサイズをwinサイズに追従 window.addEventListener('resize', () => { carousels.forEach(carousel=>{ this.slide_carousel( carousel ); }); }); }, init_sp_menu: function(){ var pc_menu_ul = document.querySelector('#pc_menu nav ul'); var sp_menu_ul = pc_menu_ul.cloneNode(true); var sp_menu_nav = document.querySelector('#sp_menu_overlay nav'); sp_menu_nav.after(sp_menu_ul); this.sp_menu_open = document.getElementById('sp_menu_open'); this.sp_menu_close = document.getElementById('sp_menu_close'); this.sp_menu_overlay= document.getElementById('sp_menu_overlay'); this.sp_menu_open.addEventListener('click', () => { this.sp_menu_overlay.classList.add('show'); this.sp_menu_open.classList.add('hide'); }); this.sp_menu_close.addEventListener('click', () => { this.sp_menu_overlay.classList.remove('show'); this.sp_menu_open.classList.remove('hide'); }); }, init_carousel: function(carousel){ carousel.current_index = 0; carousel.prev_button = carousel.querySelector('.carousel_prev'); carousel.next_button = carousel.querySelector('.carousel_next'); carousel.ul = carousel.querySelector('ul'); carousel.slides = carousel.querySelectorAll('ul li'); carousel.dots = []; // ボタンによる左右スライド carousel.prev_button.addEventListener('click', () => { carousel.current_index -= 1; this.update_carousel_buttons(carousel); this.update_carousel_dots(carousel); this.slide_carousel(carousel); }); carousel.next_button.addEventListener('click', () => { carousel.current_index += 1; this.update_carousel_buttons(carousel); this.update_carousel_dots(carousel); this.slide_carousel(carousel); }); // カルーセル下部に表示する丸ボタン生成 for (let i = 0; i < carousel.slides.length; i++) { var button = document.createElement('button'); button.addEventListener('click', () => { carousel.current_index = i; this.update_carousel_dots(carousel); this.update_carousel_buttons(carousel); this.slide_carousel(carousel); }); carousel.dots.push(button); carousel.querySelector('nav').appendChild(button); } carousel.dots[0].classList.add('current'); }, init_tab_menu: function(tab_menu){ var this_obj = this; var tab_menu_items = tab_menu.querySelectorAll('ul li a'); var tab_menu_contents = tab_menu.querySelectorAll('section'); for (let i = 0; i < tab_menu_items.length; i++) { tab_menu_items[i].addEventListener('click', event => { event.preventDefault(); tab_menu_items.forEach(item => { item.classList.remove('active'); }); tab_menu_items[i].classList.add('active'); tab_menu_contents.forEach(content => { content.classList.remove('active'); }); tab_menu_contents[i].classList.add('active'); }); } }, update_carousel_buttons: function (carousel) { carousel.prev_button.classList.remove('hidden'); carousel.next_button.classList.remove('hidden'); if (carousel.current_index == 0) { carousel.prev_button.classList.add('hidden'); } if (carousel.current_index === carousel.slides.length - 1) { carousel.next_button.classList.add('hidden'); } }, slide_carousel: function(carousel) { var slide_w = carousel.slides[0].getBoundingClientRect().width; var current_index = carousel.current_index; carousel.ul.style.transform = `translateX(${-1 * slide_w * current_index}px)`; }, update_carousel_dots: function(carousel) { carousel.dots.forEach(dot => { dot.classList.remove('current'); }); carousel.dots[carousel.current_index].classList.add('current'); } }; var win_base = new WindowBase(); win_base.init_window(); }