HTML・CSS・JavaScriptを使ったポートフォリオwebデザインをPCを使って作成していきます。
動画
ソースコード
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Portfolio</title>
<!-- style -->
<link rel="stylesheet" href="style.css">
<!-- boxicons -->
<link href='https://unpkg.com/boxicons@2.1.2/css/boxicons.min.css' rel='stylesheet'>
<!-- swiper -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@8/swiper-bundle.min.css" />
</head>
<body>
<!-- header -->
<header id="header" class="header">
<nav id="nav" class="nav">
<a href="#" class="logo">
Portfolio
</a>
<div id="navMenu" class="nav-menu">
<ul class="nav-links">
<li><a href="#about" class="nav-link about ">About</a></li>
<li><a href="#skills" class="nav-link skills">Skills</a></li>
<li><a href="#works" class="nav-link works">Works</a></li>
<li><a href="#contact" class="nav-link contact">Contact</a></li>
<li id="theme" class="theme"></li>
</ul>
</div>
<div class="nav-toggle" id="navToggle">
<div class="line top"></div>
<div class="line middle"></div>
<div class="line bottom"></div>
</div>
</nav>
</header>
<main>
<!-- top -->
<section id="top">
<div class="container top-container">
<div class="top-title right">
<h1>Hi, I am John doe.</h1>
<p>I am a web designer <br>
You can get a nice website.</p>
<button>Contact me</button>
</div>
<div class="top-image left">
<img src="./img/top.png" alt="">
</div>
</div>
</section>
<!-- about -->
<section id="about">
<div class="container about-container">
<h2 class="section-title">About me</h2>
<div class="about-wrapper">
<div class="about-image right">
<img src="./img/about.png" alt="">
</div>
<div class="about-title left">
<h2>web designer</h2>
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Minus rerum quia commodi,
architecto perspiciatis aut? Porro accusantium dicta adipisci eius.</p>
</div>
</div>
</div>
</section>
<!-- skills -->
<section id="skills">
<div class="container skills-container">
<h2 class="section-title">Skills</h2>
<div class="skills-wrapper">
<div class="skill-bar">
<div class="skill-wrapper">
<p>HTML</p>
<span class="score count" data-max="80">0%</span>
<div class="bar progress" style="--max: 80%"></div>
</div>
<div class="skill-wrapper">
<p>CSS</p>
<span class="score count" data-max="60">0%</span>
<div class="bar progress" style="--max: 60%"></div>
</div>
<div class="skill-wrapper">
<p>JavaScript</p>
<span class="score count" data-max="90">0%</span>
<div class="bar progress" style="--max: 90%"></div>
</div>
<div class="skill-wrapper">
<p>PHP</p>
<span class="score count" data-max="100">0%</span>
<div class="bar progress" style="--max: 100%"></div>
</div>
</div>
<div class="skill-icon">
<i class='bx bxl-html5'></i>
<i class="bx bxl-css3"></i>
<i class="bx bxl-javascript"></i>
<i class="bx bxl-php"></i>
</div>
</div>
</div>
</section>
<!-- works -->
<section id="works">
<div class="container works-container">
<h2 class="section-title">Works</h2>
<div class="swiper-container">
<div class="swiper">
<div class="swiper-wrapper">
<div class="swiper-slide">
<div class="card">
<img src="./img/works1.jpg" alt="">
<h4>Designer</h4>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Expedita, reiciendis?
</p>
</div>
</div>
<div class="swiper-slide">
<div class="card">
<img src="./img/works2.jpg" alt="">
<h4>Designer</h4>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Expedita, reiciendis?
</p>
</div>
</div>
<div class="swiper-slide">
<div class="card">
<img src="./img/works3.jpg" alt="">
<h4>Designer</h4>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Expedita, reiciendis?
</p>
</div>
</div>
<div class="swiper-slide">
<div class="card">
<img src="./img/works4.jpg" alt="">
<h4>Designer</h4>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Expedita, reiciendis?
</p>
</div>
</div>
</div>
</div>
<div class="swiper-scrollbar"></div>
<div class="swiper-pagination"></div>
</div>
</div>
</section>
<!-- contact -->
<section id="contact">
<div class="container contact-container">
<h2 class="section-title">Contact</h2>
<div class="contact-wrapper">
<div class="info-wrapper up">
<div class="info">
<span><i class="bx bx-phone"></i>tel</span>
<p>000-0000-0000</p>
</div>
<div class="info">
<span><i class="bx bx-envelope"></i>E-mail</span>
<p>aaaaaa@test.com</p>
</div>
<div class="info">
<span><i class="bx bx-phone"></i>address</span>
<p>Lorem, ipsum dolor.</p>
</div>
<div class="map">
<iframe
src="https://www.google.com/maps/embed?pb=!1m14!1m12!1m3!1d809.9140237029537!2d139.81065169500658!3d35.71007965146917!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!5e0!3m2!1sja!2sjp!4v1662694442859!5m2!1sja!2sjp"
width="auto" height="250" style="border:0;" allowfullscreen="" loading="lazy"
referrerpolicy="no-referrer-when-downgrade"></iframe>
</div>
</div>
<div class="forms-wrapper down">
<form action="">
<div class="form-wrapper">
<label for="name">name</label>
<input type="text" name="text" id="name">
</div>
<div class="form-wrapper">
<label for="email">E-mail</label>
<input type="email" name="email" id="email">
</div>
<div class="form-wrapper">
<label for="content">content</label>
<textarea name="content" id="content" cols="30" rows="10"></textarea>
</div>
<button>Submit</button>
</form>
</div>
</div>
</div>
</section>
</main>
<!-- footer -->
<footer>
<div class="sns">
<div class="sns-title">Follow me</div>
<div class="sns-wrapper">
<a href="" class="jump" style="--i: .2s;"><i class="bx bxl-twitter"></i></a>
<a href="" class="jump" style="--i: .4s;"><i class="bx bxl-google"></i></a>
<a href="" class="jump" style="--i: .6s;"><i class="bx bxl-instagram"></i></a>
<a href="" class="jump" style="--i: .8s;"><i class="bx bxl-youtube"></i></a>
<a href="" class="jump" style="--i: 1s;"><i class="bx bxl-facebook-square"></i></a>
</div>
</div>
</footer>
<!-- scrollTop -->
<a href="#top" id="scrollTop">
<i class="bx bxs-up-arrow-alt"></i>
</a>
<!-- swiper -->
<script src="https://cdn.jsdelivr.net/npm/swiper@8/swiper-bundle.min.js"></script>
<!-- js -->
<script src="script.js"></script>
</body>
</html>
/* web font */
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--font: 'Poppins', sans-serif;
--nav-height: 8rem;
--max-width: 1024px;
--container-padding: var(--nav-height) 4rem 0 4rem;
--gap: 2rem;
--bg-color: #fff;
--text-color: #000;
--main-color: rgb(255, 213, 135);
}
@media (prefers-color-scheme: dark) {
:root {
--bg-color: #000;
--text-color: #fff;
}
}
/*=== Font ratio ===*/
html {
scroll-behavior: smooth;
font-size: 62.5%;
}
body {
font-family: var(--font);
font-size: 1.6rem;
color: var(--text-color);
background: var(--bg-color);
}
a {
text-decoration: none;
color: var(--text-color);
}
ul {
list-style: none;
}
/* color */
button {
color: var(--text-color);
}
input,
textarea {
color: var(--text-color);
}
.line {
background: var(--text-color);
}
/* header */
header {
width: 100%;
position: fixed;
top: 0;
left: 0;
z-index: 100;
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
}
.nav {
width: 100%;
max-width: var(--max-width);
height: var(--nav-height);
display: flex;
justify-content: space-between;
align-items: center;
margin: 0 auto;
padding: 0 3rem;
}
.logo,
.nav-toggle {
cursor: pointer;
}
.logo {
font-weight: bold;
font-size: 2rem;
z-index: 100;
position: relative;
padding-left: 25px;
}
.logo::before {
content: '';
position: absolute;
left: -10px;
top: 50%;
transform: translateY(-50%);
width: 25px;
height: 25px;
background: var(--main-color);
mask: url("./img/icon1.svg");
mask-size: contain;
mask-repeat: no-repeat;
mask-position: center;
-webkit-mask: url("./img/icon1.svg");
-webkit-mask-size: contain;
-webkit-mask-repeat: no-repeat;
-webkit-mask-position: center;
z-index: -1;
}
.nav-links {
display: flex;
align-items: center;
justify-content: center;
gap: var(--gap);
}
/* indicator */
.nav-link {
position: relative;
}
.nav-link.active::before {
content: '';
position: absolute;
bottom: -5px;
left: 50%;
transform: translateX(-50%);
width: 20px;
height: 2px;
border-radius: 2px;
background: var(--main-color);
}
.theme {
cursor: pointer;
padding: .5rem;
z-index: 200;
display: flex;
}
/* hamburger */
.nav-toggle {
z-index: 200;
display: none;
padding: .5rem;
justify-content: center;
align-items: center;
flex-direction: column;
}
.nav-toggle .line {
width: 20px;
height: 2px;
border-radius: 1px;
transition: transform .5s, opacity .5s;
transform-origin: left;
}
.nav-toggle .top {
margin-bottom: 5px;
}
.nav-toggle .bottom {
margin-top: 5px;
}
#nav.toggle .top {
transform: rotate(45deg);
}
#nav.toggle .middle {
opacity: 0;
}
#nav.toggle .bottom {
transform: rotate(-45deg);
}
/* responsive nav */
@media screen and (max-width: 768px) {
.nav-menu {
background: var(--bg-color);
position: fixed;
top: 0;
right: -50%;
width: 50%;
height: 100vh;
padding-top: var(--nav-height);
transition: transform .5s ease-in-out;
z-index: 120;
}
#nav.toggle .nav-menu {
transform: translateX(-100%);
}
.nav-toggle {
display: flex;
}
.nav-links {
flex-direction: column;
}
.nav-links li {
height: var(--nav-height);
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
}
/* main */
.container {
width: 100%;
max-width: var(--max-width);
padding: var(--container-padding);
margin: 0 auto;
}
.section-title {
position: relative;
margin: 4rem 0;
text-align: center;
}
.section-title::before {
content: '';
position: absolute;
bottom: -5px;
left: 50%;
transform: translateX(-50%);
width: 50px;
height: 3px;
border-radius: 2px;
background: var(--main-color);
}
::selection {
background: var(--main-color);
}
button {
padding: 1rem 1.5rem;
position: relative;
background: transparent;
border: 2px solid;
top: -5px;
left: -5px;
transition: top .4s, left .4s;
}
button:hover {
top: 0;
left: 0;
}
button::before {
content: '';
position: absolute;
top: 10px;
left: 10px;
width: 100%;
height: 100%;
background: var(--main-color);
z-index: -10;
transition: top .4s, left .4s;
}
button:hover::before {
top: 0;
left: 0;
}
/* top */
.top-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: var(--gap);
height: 90vh;
}
.top-image {
width: 100%;
height: 100%;
position: relative;
}
.top-image::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
height: 100%;
background: var(--main-color);
mask: url('./img/haikei.svg');
mask-size: contain;
mask-repeat: no-repeat;
mask-position: center;
-webkit-mask: url('./img/haikei.svg');
-webkit-mask-size: contain;
-webkit-mask-repeat: no-repeat;
-webkit-mask-position: center;
z-index: -1;
}
.top-image img {
width: 100%;
height: 100%;
object-fit: contain;
}
.top-title {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
gap: var(--gap);
}
.top-title h1 {
font-size: 4.2rem;
font-weight: bold;
}
.top-title p {
font-size: 1.8rem;
letter-spacing: .2rem;
}
@media screen and (max-width: 768px) {
.top-container {
grid-template-columns: 1fr;
}
.top-image {
grid-row: 1 /2;
max-height: 400px;
}
}
/* about */
.about-wrapper {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: var(--gap);
align-items: center;
}
.about-image {
width: 100%;
height: 100%;
position: relative;
}
.about-image::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
height: 100%;
background: var(--main-color);
mask: url('./img/haikei2.svg');
mask-size: contain;
mask-repeat: no-repeat;
mask-position: center;
-webkit-mask: url('./img/haikei2.svg');
-webkit-mask-size: contain;
-webkit-mask-repeat: no-repeat;
-webkit-mask-position: center;
z-index: -1;
}
.about-image img {
width: 100%;
height: 100%;
object-fit: contain;
}
.about-title {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
gap: var(--gap);
}
.about-title h2 {
font-size: 4.2rem;
font-weight: bold;
}
.about-title p {
font-size: 1.8rem;
letter-spacing: .2rem;
line-height: 3rem;
}
@media screen and (max-width: 768px) {
.about-wrapper {
grid-template-columns: 1fr;
}
.about-image {
grid-row: 1 / 2;
max-height: 400px;
}
}
/* skills */
.skills-wrapper {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: var(--gap);
}
.skills-wrapper .skill-wrapper {
width: 100%;
height: 50px;
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
box-shadow: 0 0 5px 0px #ccc;
padding: 1rem;
border-radius: 5px;
margin: 2rem 0;
}
.bar {
content: '';
position: absolute;
bottom: 0;
left: 0;
height: 5px;
background: var(--main-color);
border-radius: 5px;
}
.skill-icon {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(2, 1fr);
justify-content: center;
align-items: center;
}
.skill-icon i {
font-size: 10rem;
padding: 1rem;
border-radius: 50%;
color: rgb(230, 230, 230);
}
@media screen and (max-width: 768px) {
.skills-wrapper {
grid-template-columns: 1fr;
}
.skill-icon {
grid-row: 1/ 2;
}
}
/* works */
/* swiper */
.swiper-container {
position: relative;
padding: 0 5rem 5rem 5rem;
}
.swiper {
width: 100%;
}
.swiper-slide {
padding: 2rem;
display: flex;
justify-content: center;
align-items: center;
}
.swiper-pagination-bullet {
margin: 0 1rem !important;
opacity: 1 !important;
background: #ccc !important;
}
.swiper-pagination-bullet-active {
background: var(--main-color) !important;
}
/* card */
.card {
width: 100%;
max-width: 250px;
padding: 2rem 1rem;
border-radius: .5rem;
box-shadow: 0px 0px 5px #ccc;
}
.card img {
width: 100%;
height: 100px;
object-fit: cover;
}
.card h4 {
font-size: 2rem;
margin: 1rem 0;
}
.card p {
font-size: 1.4rem;
}
/* contact */
.contact-wrapper {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: var(--gap);
}
/* info */
.info {
padding: 1rem;
}
.info span {
font-weight: bold;
display: flex;
justify-content: flex-start;
align-items: center;
gap: .5rem;
}
.map {
margin: 2rem 0;
display: flex;
justify-content: center;
align-items: center;
}
/* form */
.forms-wrapper {
margin: 0 auto 2rem;
}
.form-wrapper input,
.form-wrapper textarea {
padding: .5rem;
margin-bottom: 2rem;
background: transparent;
width: 100%;
}
.form-wrapper input:focus,
.form-wrapper textarea:focus {
outline: none;
}
.form-wrapper label {
font-weight: bold;
display: inline-block;
margin-bottom: .5rem
}
.forms-wrapper button {
width: 100%;
}
@media screen and (max-width: 768px) {
.contact-wrapper {
grid-template-columns: 1fr;
}
.forms-wrapper {
grid-row: 1 / 2;
}
}
/* footer */
footer {
height: 200px;
width: 100%;
max-width: var(--max-width);
margin: 0 auto;
text-align: center;
}
/* sns */
.sns {
margin-top: 4rem;
}
.sns-title {
margin: 2rem 0;
}
.sns-wrapper {
display: flex;
gap: var(--gap);
justify-content: center;
}
.sns-wrapper i {
font-size: 3rem;
color: #ccc;
cursor: pointer;
}
/* scrollTop */
#scrollTop {
position: fixed;
bottom: 50px;
right: 50px;
width: 20px;
height: 20px;
border-radius: 5px;
padding: 2rem;
background: var(--main-color);
display: flex;
justify-content: center;
align-items: center;
display: none;
}
#scrollTop i {
font-size: 3rem;
}
/* animation */
.left {
opacity: 0;
}
.left.active {
animation: left 1.5s ease-in-out forwards;
}
@keyframes left {
from {
opacity: 0;
transform: translateX(50px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.right {
opacity: 0;
}
.right.active {
animation: right 1.5s ease-in-out forwards;
}
@keyframes right {
from {
opacity: 0;
transform: translateX(-50px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.up {
opacity: 0;
}
.up.active {
animation: up 1.5s ease-in-out forwards;
}
@keyframes up {
from {
opacity: 0;
transform: translateY(50px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.down {
opacity: 0;
}
.down.active {
animation: down 1.5s ease-in-out forwards;
}
@keyframes down {
from {
opacity: 0;
transform: translateY(-50px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.progress.active {
animation: progress 1.5s ease-in-out forwards;
}
@keyframes progress {
from {
width: 0;
}
to {
width: var(--max);
}
}
.jump {
opacity: 0;
}
.jump.active {
animation: jump 1.5s var(--i) ease-in-out forwards;
}
@keyframes jump {
0% {
transform: translateY(0px);
opacity: 0;
}
25% {
transform: translateY(-10px);
opacity: .25;
}
50% {
transform: translateY(0px);
opacity: .5;
}
75% {
transform: translateY(-5px);
opacity: .75;
}
100% {
transform: translateY(0px);;
opacity: 1;
}
}
// nav
const nav = document.getElementById('nav'),
navToggle = document.getElementById('navToggle'),
navLinks = document.querySelectorAll('.nav-link');
navToggle?.addEventListener('click', function () {
nav.classList.toggle('toggle');
})
navLinks.forEach(function (li) {
li.addEventListener('click', function () {
nav.classList.remove('toggle');
})
})
// swiper
const swiper = new Swiper('.swiper', {
direction: 'horizontal',
loop: true,
pagination: {
el: '.swiper-pagination',
clickable: true,
},
spaceBetween: 10,
slidexPerView: 1,
breakpoints: {
660: {
slidesPerView: 2,
},
900: {
slidesPerView: 3,
}
}
})
// color
let theme = document.getElementById('theme'),
theme_icon,
el = document.createElement('i');
if (window.matchMedia('(prefers-color-scheme: dark)').matches === true) {
el.classList.add('bx', 'bxs-sun');
theme_icon = 'sun';
} else {
el.classList.add('bx', 'bxs-moon');
theme_icon = 'moon';
}
theme.appendChild(el);
theme.addEventListener('click', function () {
let dark = getComputedStyle(document.documentElement).getPropertyValue('--bg-color'),
light = getComputedStyle(document.documentElement).getPropertyValue('--text-color');
document.documentElement.style.setProperty('--bg-color', light);
document.documentElement.style.setProperty('--text-color', dark);
if (theme_icon == 'sun') {
theme.firstElementChild.classList = 'bx bxs-moon';
theme_icon = 'moon';
} else {
theme.firstElementChild.classList = 'bx bxs-sun';
theme_icon = 'sun';
}
})
// nav observer
const scrollTop = document.getElementById('scrollTop');
const navOptions = {
rootMargin: '-50% 0px',
};
const sections = document.querySelectorAll('section');
const navObserver = new IntersectionObserver(nav_intersect, navOptions);
sections.forEach(function (section) {
navObserver.observe(section);
})
function nav_intersect(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
navLinks.forEach(function (navLink) { navLink.classList.remove('active') });
nav.querySelector('.' + entry.target.id)?.classList.add('active');
if (entry.target.id == 'top') {
scrollTop.style.display = 'none';
}
}
if (!entry.isIntersecting) {
if (entry.target.id == 'top') {
scrollTop.style.display = 'flex';
}
}
})
}
// animation observer
const animationOptions = {
threshold: [0.2],
};
const animations = document.querySelectorAll(['.left', '.right', '.up', '.down', '.progress', '.jump', '.count']);
const animationObserver = new IntersectionObserver(animation_intersect, animationOptions);
animations.forEach(function (animation) {
animationObserver.observe(animation);
})
function animation_intersect(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
if (entry.target.classList.contains('count')) {
count(entry);
} else {
entry.target.classList.add('active');
}
}
})
}
// count
function count(entry) {
let maxNum = parseFloat(entry.target.dataset.max),
counterId,
duration = 1500 / maxNum;
function countUp() {
let currentNum = parseFloat(entry.target.innerHTML);
if (currentNum < maxNum) {
entry.target.innerHTML = currentNum + 1 +'%';
}
if (currentNum == maxNum) {
clearInterval(counterId);
}
}
counterId = setInterval(countUp, duration);
}