Skeleton Profile Card
<div class="skeleton-card">
<div class="skeleton-top">
<div class="sk avatar"></div>
<div class="skeleton-info">
<div class="sk name"></div>
<div class="sk role"></div>
</div>
</div>
<div class="sk banner"></div>
<div class="sk line line-1"></div>
<div class="sk line line-2"></div>
<div class="sk line line-3"></div>
<div class="actions">
<div class="sk button"></div>
<div class="sk button"></div>
</div>
</div>
@keyframes shimmer{
from{
background-position:-300px 0;
}
to{
background-position:300px 0;
}
}
.skeleton-card{
max-width:320px;
padding:16px;
background:#fff;
border:1px solid #ece7df;
}
.sk{
background:linear-gradient(
90deg,
#ece8e2 0%,
#f8f6f2 50%,
#ece8e2 100%
);
background-size:600px 100%;
animation:shimmer 1.5s linear infinite;
}
.skeleton-top{
display:flex;
align-items:center;
gap:12px;
margin-bottom:16px;
}
.avatar{
width:44px;
height:44px;
border-radius:50%;
}
.skeleton-info{
flex:1;
}
.name{
height:12px;
width:55%;
margin-bottom:8px;
}
.role{
height:10px;
width:35%;
}
.banner{
height:120px;
border-radius:8px;
margin-bottom:14px;
}
.line{
height:10px;
border-radius:99px;
margin-bottom:8px;
}
.line-1{width:100%;}
.line-2{width:90%;}
.line-3{width:65%;}
.actions{
display:flex;
gap:10px;
margin-top:14px;
}
.button{
width:80px;
height:32px;
border-radius:999px;
}
Modern Toast Notification
<button onclick="toast('Guardado correctamente','success')">
Mostrar Toast
</button>
<div id="toast-container"></div>
#toast-container{
position:fixed;
right:24px;
bottom:24px;
display:flex;
flex-direction:column;
gap:10px;
z-index:9999;
}
.toast{
position:relative;
display:flex;
align-items:center;
gap:12px;
min-width:260px;
padding:14px 16px;
background:#fff;
border-left:4px solid;
box-shadow:0 4px 14px rgba(0,0,0,.12);
transform:translateX(40px);
opacity:0;
transition:.3s;
overflow:hidden;
}
.toast.show{
transform:translateX(0);
opacity:1;
}
.toast::after{
content:"";
position:absolute;
left:0;
bottom:0;
width:100%;
height:3px;
background:currentColor;
animation:progress 3s linear forwards;
}
.toast.success{
color:#1a7a40;
border-color:#1a7a40;
}
.toast.error{
color:#c0392b;
border-color:#c0392b;
}
.toast.info{
color:#2563eb;
border-color:#2563eb;
}
@keyframes progress{
from{width:100%;}
to{width:0;}
}
function toast(message,type='success'){
const toast=document.createElement('div');
toast.className=`toast ${type}`;
const icons={
success:'✓',
error:'✕',
info:'ⓘ'
};
toast.innerHTML=`
${icons[type]||'ⓘ'}
${message}
`;
document
.getElementById('toast-container')
.appendChild(toast);
requestAnimationFrame(()=>{
toast.classList.add('show');
});
setTimeout(()=>{
toast.classList.remove('show');
setTimeout(()=>{
toast.remove();
},300);
},3000);
}
Glass Flip Card
Alejandro
UI Designer
Skills
UI/UX
Frontend
Illustration
<div class="flip-scene">
<div class="flip-card">
<div class="flip-front">
<span class="label">Portfolio</span>
<h3>John Doe</h3>
<p>UI Designer</p>
</div>
<div class="flip-back">
<h3>Skills</h3>
<p>UI/UX</p>
<p>Frontend</p>
<p>Illustration</p>
</div>
</div>
</div>
@keyframes float{
50%{
transform:translateY(-4px);
}
}
.flip-scene{
perspective:1000px;
}
.flip-card{
width:240px;
height:140px;
position:relative;
transform-style:preserve-3d;
transition:transform .7s cubic-bezier(.2,.8,.2,1);
}
.flip-scene:hover .flip-card{
transform:rotateY(180deg);
}
.flip-front,
.flip-back{
position:absolute;
inset:0;
padding:20px;
border-radius:12px;
backface-visibility:hidden;
display:flex;
flex-direction:column;
justify-content:center;
color:#fff;
}
.flip-front{
background:linear-gradient(
135deg,
#111,
#2d2d2d
);
}
.flip-back{
background:linear-gradient(
135deg,
#FF5200,
#FF8C00
);
transform:rotateY(180deg);
}
.label{
font-size:.7rem;
text-transform:uppercase;
opacity:.7;
margin-bottom:8px;
}
.flip-front h3,
.flip-back h3{
margin:0 0 6px;
}
.flip-front p,
.flip-back p{
margin:0;
}
Expandable Sidebar
<aside class="sidebar">
<div class="logo">
<i class="ti ti-layout-sidebar"></i>
</div>
<nav class="menu">
<a href="#" class="item active">
<i class="ti ti-home"></i>
<span>Dashboard</span>
</a>
<a href="#" class="item">
<i class="ti ti-user"></i>
<span>Profile</span>
</a>
<a href="#" class="item">
<i class="ti ti-settings"></i>
<span>Settings</span>
</a>
<a href="#" class="item">
<i class="ti ti-chart-bar"></i>
<span>Analytics</span>
</a>
</nav>
<div class="user">
<div class="avatar"></div>
<span>Alejandro</span>
</div>
</aside>
.sidebar{
width:70px;
height:320px;
display:flex;
flex-direction:column;
padding:12px;
background:#111;
border-radius:18px;
overflow:hidden;
transition:.35s ease;
}
.sidebar:hover{
width:200px;
}
.logo{
height:42px;
display:flex;
align-items:center;
justify-content:center;
color:#fff;
margin-bottom:12px;
}
.menu{
flex:1;
display:flex;
flex-direction:column;
gap:8px;
}
.item{
height:42px;
display:flex;
align-items:center;
gap:12px;
padding:0 12px;
color:#fff;
text-decoration:none;
border-radius:10px;
white-space:nowrap;
}
.item:hover{
background:#1f1f1f;
}
.item.active{
background:#FF5200;
}
.item span,
.user span{
opacity:0;
transition:.25s;
}
.sidebar:hover .item span,
.sidebar:hover .user span{
opacity:1;
}
.avatar{
width:32px;
height:32px;
border-radius:50%;
background:#444;
}
.user{
display:flex;
align-items:center;
gap:12px;
padding:8px;
color:#fff;
white-space:nowrap;
}
Efecto Typewriter
Código con propósito
<p class="typewriter"> Tu texto aquí<span class="tw-cursor"></span> </p>
@keyframes type {
from { width: 0; }
to { width: 100%; }
}
@keyframes blink {
0%, 100% { opacity: 1; }
50% { opacity: 0; }
}
.typewriter {
overflow: hidden;
white-space: nowrap;
width: 0;
font-weight: 700;
font-size: 1.4rem;
animation: type 2.4s steps(30, end) forwards;
}
.tw-cursor {
display: inline-block;
width: 2px; height: 1.1em;
background: #FF5200;
margin-left: 3px;
vertical-align: middle;
animation: blink 1s step-end infinite;
}
Glassmorphism Card
<div class="glass-scene">
<div class="glass-card">
<h3>Glass Card</h3>
<p>Efecto vidrio esmerilado.</p>
</div>
</div>
.glass-scene {
background: linear-gradient(135deg, #667eea, #764ba2);
padding: 48px;
display: flex;
align-items: center;
justify-content: center;
}
.glass-card {
background: rgba(255, 255, 255, .15);
backdrop-filter: blur(14px) saturate(180%);
-webkit-backdrop-filter: blur(14px);
border: 1px solid rgba(255, 255, 255, .25);
border-radius: 12px;
padding: 28px 36px;
color: #fff;
}
.glass-card h3 {
font-size: 1rem; font-weight: 700;
margin-bottom: 6px;
}
.glass-card p { font-size: .82rem; opacity: .8; }
Grid Mosaico
<div class="mosaic"> <div class="m-a"></div> <div class="m-b"></div> <div class="m-c"></div> <div class="m-d"></div> </div>
.mosaic {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(2, 1fr);
gap: 4px;
height: 300px;
}
.m-a { grid-column: span 2; background: #111; }
.m-b { background: #FF5200; }
.m-c { background: #DEDAD3; }
.m-d {
grid-column: span 3;
background: #F8F6F2;
border: 1px solid #DEDAD3;
}
Contador Animado
<span class="counter" data-target="2500">0</span>
const obs = new IntersectionObserver(entries => {
entries.forEach(e => {
if (!e.isIntersecting) return;
const el = e.target;
const target = +el.dataset.target;
let count = 0;
const step = Math.max(1, Math.ceil(target / 60));
const run = setInterval(() => {
count = Math.min(count + step, target);
el.textContent = count.toLocaleString();
if (count >= target) clearInterval(run);
}, 16);
obs.unobserve(el);
});
}, { threshold: .5 });
document.querySelectorAll('.counter')
.forEach(c => obs.observe(c));
Texto Gradiente Animado
Diseño con propósito
<h2 class="gradient-text">Tu texto aquí</h2>
@keyframes gradMove {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
.gradient-text {
background: linear-gradient(
270deg, #FF5200, #FF8C00, #FFD700, #FF5200
);
background-size: 300% 300%;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
animation: gradMove 4s ease infinite;
font-size: 2rem;
font-weight: 800;
}
Acordeón CSS Puro
¿Qué es el Paradigma POP?
Programación Orientada a Propósito. Organiza el código según la intención de cada pieza.
¿Tiene costo?
Es completamente libre y abierto.
¿Con qué lenguajes funciona?
Con cualquier lenguaje. Es un paradigma, no una librería.
<details class="acc"> <summary class="acc-q">¿Pregunta aquí?</summary> <p class="acc-a">Respuesta aquí.</p> </details>
.acc { border-bottom: 1px solid #DEDAD3; }
.acc-q {
list-style: none;
padding: 16px 20px;
cursor: pointer;
font-weight: 600;
font-size: .88rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.acc-q::-webkit-details-marker { display: none; }
.acc-q::after {
content: '+';
color: #FF5200;
font-size: 1.2rem;
}
details[open] .acc-q::after { content: '-'; }
.acc-a {
padding: 0 20px 16px;
font-size: .82rem;
color: #5f5f5b;
line-height: 1.7;
}
Scrollbar Personalizado
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Sed do eiusmod tempor incididunt ut labore.
Ut enim ad minim veniam, quis nostrud.
Duis aute irure dolor in reprehenderit.
Excepteur sint occaecat cupidatat non proident.
Sunt in culpa qui officia deserunt mollit.
Integer nec odio, praesent libero sed cursus.
Nulla quis sem at nibh elementum imperdiet.
Fusce nec tellus sed augue semper porta.
Vestibulum lacinia arcu eget nulla facilisis.
Curabitur sodales ligula in libero pretium.
Pellentesque nibh aenean quam in scelerisque.
Proin ut ligula vel nunc egestas porttitor.
Morbi lectus risus iaculis vel suscipit.
Fusce ac turpis quis ligula lacinia aliquet.
Nulla metus metus ullamcorper vel tincidunt.
Quisque volutpat condimentum velit euismod.
Nam nec ante sed lacinia urna non mattis.
Aenean leo ligula porttitor eu consequat.
Aliquam lorem ante dapibus in viverra quis.
Phasellus viverra nulla ut metus varius.
Quisque rutrum aenean imperdiet etiam nisi.
Nam eget dui etiam rhoncus maecenas tempus.
Donec sodales sagittis magna sed consequat.
Vestibulum ante ipsum primis in faucibus.
In ac dui quis mi consectetuer lacinia.
Duis arcu tortor suscipit eget imperdiet.
Sed aliquam ultrices mauris integer ante.
Praesent blandit laoreet nibh fusce metus.
Donec vitae sapien ut libero faucibus.
/* Aplicar al contenedor con scroll */
.contenedor {
height: 200px;
overflow-y: auto;
padding: 16px;
/* Firefox */
scrollbar-width: thin;
scrollbar-color: #FF5200 #F8F6F2;
}
/* Chrome, Edge, Safari */
.contenedor::-webkit-scrollbar { width: 6px; }
.contenedor::-webkit-scrollbar-track {
background: #F8F6F2;
}
.contenedor::-webkit-scrollbar-thumb {
background: #FF5200;
border-radius: 3px;
}
.contenedor::-webkit-scrollbar-thumb:hover {
background: #111;
}
Toggle Modo Oscuro
<button onclick="toggleDark()"> Modo oscuro </button>
:root {
--bg: #F8F6F2;
--text: #111;
}
[data-theme="dark"] {
--bg: #111;
--text: #F8F6F2;
}
body {
background: var(--bg);
color: var(--text);
transition: all .3s;
}
function toggleDark() {
const isDark =
document.documentElement.dataset.theme === 'dark';
document.documentElement.dataset.theme =
isDark ? '' : 'dark';
btn.textContent = isDark
? 'Modo oscuro' : 'Modo claro';
localStorage.setItem(
'theme', isDark ? 'light' : 'dark'
);
}
// Recordar al cargar
if (localStorage.getItem('theme') === 'dark') {
toggleDark();
}
Tabs con JavaScript
<div class="tabs"> <button class="tab active" data-tab="a">Tab 1</button> <button class="tab" data-tab="b">Tab 2</button> </div> <div class="panel" data-panel="a">Contenido A</div> <div class="panel hidden" data-panel="b">Contenido B</div>
.tabs {
display: flex; gap: 0;
border-bottom: 1px solid #DEDAD3;
}
.tab {
padding: 10px 18px; border: none;
background: transparent; font-weight: 600;
font-size: .82rem; cursor: pointer;
color: #5f5f5b;
border-bottom: 2px solid transparent;
transition: all .2s;
}
.tab.active {
color: #FF5200;
border-bottom-color: #FF5200;
}
.panel { padding: 16px; font-size: .85rem; color: #5f5f5b; }
.panel.hidden { display: none; }
document.querySelectorAll('.tab').forEach(tab => {
tab.addEventListener('click', () => {
const target = tab.dataset.tab;
document.querySelectorAll('.tab').forEach(
t => t.classList.remove('active')
);
document.querySelectorAll('.panel').forEach(
p => p.classList.toggle(
'hidden', p.dataset.panel !== target
)
);
tab.classList.add('active');
});
});
DNA Loader
<div class="dna-loader"> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> </div>
.dna-loader{
display:flex;
gap:10px;
}
.dna-loader span{
width:10px;
height:10px;
border-radius:50%;
background:#FF5200;
animation:dna .9s infinite ease-in-out;
}
.dna-loader span:nth-child(even){
background:#FFD700;
}
.dna-loader span:nth-child(2){animation-delay:.1s;}
.dna-loader span:nth-child(3){animation-delay:.2s;}
.dna-loader span:nth-child(4){animation-delay:.3s;}
.dna-loader span:nth-child(5){animation-delay:.4s;}
.dna-loader span:nth-child(6){animation-delay:.5s;}
.dna-loader span:nth-child(7){animation-delay:.6s;}
.dna-loader span:nth-child(8){animation-delay:.7s;}
@keyframes dna{
0%,100%{
transform:translateY(-12px) scale(.7);
}
50%{
transform:translateY(12px) scale(1.2);
}
}
Efecto Ripple
<button class="ripple-btn">Haz clic</button>
.ripple-btn {
position: relative; overflow: hidden;
padding: 12px 28px; border: none;
background: #111; color: #fff;
font-weight: 600; font-size: .85rem;
cursor: pointer;
}
.ripple {
position: absolute; border-radius: 50%;
transform: scale(0); pointer-events: none;
background: rgba(255, 255, 255, .3);
animation: ripple-anim .55s linear;
}
@keyframes ripple-anim {
to { transform: scale(4); opacity: 0; }
}
document.querySelectorAll('.ripple-btn')
.forEach(btn => {
btn.addEventListener('click', function(e) {
const r = this.getBoundingClientRect();
const size = Math.max(r.width, r.height);
const el = document.createElement('span');
el.className = 'ripple';
el.style.cssText =
'width:' + size + 'px;' +
'height:' + size + 'px;' +
'left:' + (e.clientX-r.left-size/2) + 'px;' +
'top:' + (e.clientY-r.top-size/2) + 'px;';
this.appendChild(el);
setTimeout(() => el.remove(), 600);
});
});
Card Tilt 3D
<div class="tilt-scene">
<div class="tilt-card">
<h3>Minnt Studio</h3>
<p>Diseño con propósito</p>
</div>
</div>
.tilt-scene { perspective: 600px; display: flex;
align-items: center; justify-content: center; }
.tilt-card {
background: #111; color: #fff;
padding: 28px 36px;
border: 1px solid #222;
transition: transform .1s ease;
transform-style: preserve-3d;
}
.tilt-card h3 {
font-size: .95rem; font-weight: 700;
margin-bottom: 6px;
}
.tilt-card p { font-size: .75rem; color: #888; }
const card = document.querySelector('.tilt-card');
const scene = document.querySelector('.tilt-scene');
scene.addEventListener('mousemove', e => {
const r = card.getBoundingClientRect();
const x = (e.clientX - r.left) / r.width - .5;
const y = (e.clientY - r.top) / r.height - .5;
card.style.transform =
'rotateY(' + (x * 18) + 'deg)' +
' rotateX(' + (-y * 18) + 'deg)';
});
scene.addEventListener('mouseleave', () => {
card.style.transform = 'rotateY(0) rotateX(0)';
});
Lazy Load con Observer
<img class="lazy" data-src="imagen-real.jpg" src="placeholder.jpg" alt="Descripción" >
.lazy {
opacity: 0;
transition: opacity .5s ease;
width: 100%;
display: block;
}
.lazy.loaded {
opacity: 1;
}
const obs = new IntersectionObserver(entries => {
entries.forEach(e => {
if (!e.isIntersecting) return;
const img = e.target;
img.src = img.dataset.src;
img.onload = () => img.classList.add('loaded');
obs.unobserve(img);
});
}, { rootMargin: '100px' });
document.querySelectorAll('img.lazy')
.forEach(img => obs.observe(img));
Sticky Header en Scroll
<header class="sticky-nav">Navbar</header> <main><!-- contenido --></main>
.sticky-nav {
position: sticky; top: 0;
background: #F8F6F2;
padding: 16px 24px;
border-bottom: 1px solid #DEDAD3;
font-weight: 700; font-size: .88rem;
transition: box-shadow .25s, background .25s;
z-index: 100;
}
.sticky-nav.scrolled {
background: rgba(248, 246, 242, .9);
backdrop-filter: blur(8px);
box-shadow: 0 2px 20px rgba(0, 0, 0, .06);
}
const nav = document.querySelector('.sticky-nav');
window.addEventListener('scroll', () => {
nav.classList.toggle(
'scrolled', window.scrollY > 10
);
});