<div id="app">
<main>
<div class="card-grid">
<div class="card-grid__inner">
<template v-for="index in 4">
<card-message></card-message>
<card-todo></card-todo>
<card-progress></card-progress>
</template>
</div>
</div>
<hr>
<div class="card-grid card-grid--alt">
<div class="card-grid__inner">
<template v-for="index in 2">
<card-message></card-message>
<card-todo></card-todo>
<card-progress></card-progress>
</template>
</div>
</div>
</main>
</div>
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;600;700&display=swap');
* {
box-sizing: border-box;
}
body {
background: #FAFAFA;
font-family: 'Nunito', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
main {
width: 90%;
margin: 50px auto;
max-width: 1100px;
}
.card-grid {
container-type: inline-size;
container-name: card-grid;
margin-bottom: 50px;
&--alt {
max-width: 500px;
margin-top: 50px;
}
&__inner {
--cols: 4;
display: grid;
grid-gap: 2cqw;
grid-template-columns: repeat(var(--cols), 1fr);
@container card-grid (max-width: 900px) {
--cols: 3;
grid-gap: 3cqw;
}
@container card-grid (max-width: 600px) {
--cols: 2;
grid-gap: 4cqw;
}
}
}
.card {
container-type: size;
container-name: card;
aspect-ratio: 1;
color: var(--color);
&__inner {
font-size: 5cqw;
height: 100%;
position: relative;
display: flex;
flex-direction: column;
align-items: flex-start;
padding: 2em;
background: var(--bg);
border-radius: 5px;
border: 2px solid var(--border);
}
&--light {
--color: #777;
--bg: #FFF;
--border: #D8D8D8;
}
&--mid {
--color: #777;
--bg: #E3E3E3;
--border: #B9B9B9;
}
&--dark {
--color: #FFF;
--bg: #504b4b;
--border: #1c1c1c;
}
h6 {
margin-top: 0;
font-size: 0.9em;
text-transform: uppercase;
font-weight: 400;
letter-spacing: 0.2em;
position: relative;
&:before {
content: '';
position: absolute;
bottom: -0.5em;
left: 0;
width: 2em;
height: 2px;
background: currentColor;
opacity: 0.1;
}
}
h2 {
margin-top: 0;
margin-bottom: 0.5em;
font-size: 1.4em;
}
p {
font-size: 1em;
margin-top: 0;
opacity: 0.8;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
display: -webkit-box;
overflow: hidden;
}
&__link {
margin-top: auto;
text-decoration: none;
font-size: 1.2em;
color: currentColor;
margin-bottom: -0.4em;
display: inline-flex;
align-items: center;
svg {
stroke: currentColor;
margin-left: 0.5em;
opacity: 0.5;
width: 1em;
height: 1em;
}
}
}
.todo {
background: #FFF;
width: 100%;
border-radius: 999px;
padding: 0.5em 1.5em;
text-decoration: none;
color: currentColor;
display: inline-flex;
align-items: center;
justify-content: space-between;
& + & {
margin-top: 0.5em;
}
svg {
stroke: currentColor;
opacity: 0.5;
width: 1em;
height: 1em;
}
}
.pie-chart {
display: block;
width: 100%;
height: 10em;
font-size: 1em;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
&__1 {
stroke: #777;
fill: none;
stroke-width: 2;
stroke-linecap: round;
animation: progress 1s ease-out forwards;
}
&__2 {
stroke: #EEE;
fill: none;
stroke-width: 2;
animation: progress 1s ease-out forwards;
}
}
.percentage {
position: absolute;
font-size: 3em;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
text-align: center;
line-height: 1;
font-weight: bold;
span {
font-size: 40%;
font-weight: lighter;
}
}
@keyframes progress {
0% {
stroke-dasharray: 0 100;
}
}
View Compiled
Vue.component('arrow', {
template: `<svg xmlns="http://www.w3.org/2000/svg" width="13.889" height="14.718" viewBox="0 0 13.889 14.718">
<g transform="translate(1 1.414)">
<path d="M7.5,18H19.389" transform="translate(-7.5 -12.055)" fill="none" stroke-linecap="round"
stroke-linejoin="round" stroke-width="2"/>
<path d="M18,7.5l5.945,5.945L18,19.389" transform="translate(-12.055 -7.5)" fill="none"
stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
</svg>`
});
Vue.component('card-message', {
template: `
<div class="card card--light">
<div class="card__inner">
<h6>Message</h6>
<h2>Lorem Ipsum Dolor</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.
Ab accusamus accusantium asperiores beatae eaque eveniet explicabo
consectetur adipisicing elit.</p>
<a href="#" class="card__link">
Read More
<arrow/>
</a>
</div>
</div>`
});
Vue.component('card-todo', {
template: `
<div class="card card--mid">
<div class="card__inner">
<h6>Todo</h6>
<a :key="index" href="#" class="todo" v-for="index in 3">Lorem Ipsum
<arrow/>
</a>
<a href="#" class="card__link">
See All
<arrow/>
</a>
</div>
</div>`
});
Vue.component('card-progress', {
template: `
<div class="card card--dark">
<div class="card__inner">
<h6>Progress</h6>
<svg viewBox="0 0 36 36" class="pie-chart">
<path class="pie-chart__1"
stroke-dasharray="100, 100"
d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831"/>
<path class="pie-chart__2"
stroke-dasharray="70, 100"
d="M18 2.0845
a 15.9155 15.9155 0 0 1 0 31.831
a 15.9155 15.9155 0 0 1 0 -31.831"
/>
</svg>
<div class="percentage">
70 <span>%</span>
</div>
<a href="#" class="card__link">
More Info
<arrow/>
</a>
</div>
</div>`
});
let app = new Vue({
el: '#app',
})
This Pen doesn't use any external CSS resources.