Rompiendo las reglas del UX/UI
ElSalto
Rompiendo las reglas del UX/UI
Web
← Arrastra para explorar →
Efecto divisor (Split) — Demo + Código listo para copiar
Arrastra horizontalmente para revelar el contenido. Accesible por teclado (← →), responsive y sin dependencias.
Rompiendo las reglas del UX/UI
ElSalto
Rompiendo las reglas del UX/UI
Web
← Arrastra para explorar →
Cómo funciona
- Capa izquierda (.split-left) cambia su
widthentre 10% y 90% según la posición del puntero. - Divisor (.split-divider) acompaña visualmente el corte.
- Micro-interacciones: parallax sutil y halo siguiendo el cursor.
- Accesibilidad: control por teclado con flechas (atributos ARIA de “slider”).
HTML
<section class="split-stage" role="slider" aria-label="Control deslizante de división de pantalla" aria-valuemin="10" aria-valuemax="90" aria-valuenow="60" tabindex="0">
<div class="split-right" aria-hidden="true"></div>
<div class="split-left" aria-hidden="true" id="splitLeft"></div>
<div class="split-divider" aria-hidden="true"></div>
<div class="side side--left" aria-hidden="true">
<div class="side__inner">
<h3 class="title title--left">
Rompiendo las reglas del UX/UI<br />
<span class="fancy">ElSalto</span>
</h3>
</div>
</div>
<div class="side side--right">
<div class="side__inner">
<h3 class="title title--right">
Rompiendo las reglas del UX/UI<br />
<span class="fancy">Web</span>
</h3>
</div>
</div>
<div class="split-hint" aria-hidden="true">← Arrastra para explorar →</div>
</section>
CSS
:root{
--brand:#a0e234;
--bg:#0b0b0f;
--fg:#e7e7ea;
--muted:#a3a3ad;
--divider-size: 3px;
--halo-size: 240px;
--radius: 16px;
}
.split-stage{
position: relative;
isolation: isolate;
width: min(1100px, 96vw);
aspect-ratio: 16/9;
margin-inline: auto;
border-radius: var(--radius);
overflow: clip;
background: radial-gradient(1200px 1200px at var(--cursor-x, 50%) var(--cursor-y, 50%),
color-mix(in oklab, var(--brand) 16%, transparent) 0%,
transparent 45%),
linear-gradient(180deg, #0d0d12, #0a0a0c);
box-shadow:
0 10px 30px rgba(0,0,0,.35),
inset 0 0 0 1px rgba(255,255,255,.06);
}
.split-left,
.split-right{
position:absolute; inset:0;
transition: width .18s ease;
will-change: width;
}
.split-left{
width:60%;
background:
linear-gradient(180deg, color-mix(in oklab, var(--brand) 14%, transparent), transparent 70%),
radial-gradient(1000px 900px at 10% 10%, rgba(160,226,52,.12), transparent 60%),
linear-gradient(135deg, #12131a, #0c0e12 55%, #0a0b0e);
clip-path: inset(0 0 0 0 round var(--radius) 0 0 var(--radius));
}
.split-right{
background:
linear-gradient(180deg, rgba(255,255,255,.04), transparent 60%),
linear-gradient(135deg, #0b0c10, #0e1016 60%, #0a0b0e);
}
.split-divider{
position:absolute; top:0; bottom:0; left:60%;
width:var(--divider-size);
background: linear-gradient(180deg, #ffffff, #ffffff) padding-box,
linear-gradient(180deg, color-mix(in oklab, var(--brand) 55%, #ffffff), transparent) border-box;
border-left:1px solid color-mix(in oklab, var(--brand) 65%, #ffffff);
border-right:1px solid rgba(255,255,255,.06);
box-shadow:
0 0 0 3px rgba(255,255,255,.03),
0 0 30px color-mix(in oklab, var(--brand) 35%, transparent);
pointer-events:none;
}
.side{
position:absolute; inset:0; display:grid; place-items:center; padding:clamp(16px, 4vw, 40px);
}
.side--left{ color: var(--fg); opacity: var(--left-opacity, 1); transform: translateX(calc(var(--left-shift, 0) * 1rem)); }
.side--right{ color: var(--fg); opacity: var(--right-opacity, 1); transform: translateX(calc(var(--right-shift, 0) * 1rem)); }
.side__inner{ text-align:center; filter: drop-shadow(0 6px 24px rgba(0,0,0,.35)); }
.title{
font-family: ui-sans-serif, system-ui, "Segoe UI", Roboto, Inter, "Helvetica Neue", Arial;
font-weight: 800; line-height: 1.05;
letter-spacing: -0.02em;
font-size: clamp(28px, 5.5vw, 56px);
}
.title--left .fancy{ color: var(--brand); }
.title--right .fancy{
background: linear-gradient(90deg, var(--brand), #d7ff86 60%, #fff);
-webkit-background-clip: text; background-clip: text; color: transparent;
}
.split-stage::after{
content:""; position:absolute; inset:0;
background:
radial-gradient(var(--halo-size) var(--halo-size) at var(--cursor-x, 50%) var(--cursor-y, 50%),
color-mix(in oklab, var(--brand) 18%, transparent), transparent 60%);
mix-blend-mode: soft-light;
pointer-events:none;
}
.split-hint{
position:absolute; bottom:10px; left:50%; translate:-50% 0;
font-size: 12px; letter-spacing:.02em;
color: var(--muted);
background: rgba(255,255,255,.06);
border:1px solid rgba(255,255,255,.08);
padding:6px 10px; border-radius: 999px;
backdrop-filter: blur(8px);
}
.split-stage:focus{
outline: 2px solid var(--brand);
outline-offset: 4px;
}
@media (max-width: 768px){
.split-stage{ aspect-ratio: 4/5; }
.split-hint{ font-size: 11px; bottom:8px; }
}
@media (prefers-reduced-motion: reduce){
.split-left, .side--left, .side--right{ transition: none !important; }
}
JS
(() => {
const left = document.getElementById('splitLeft');
const stage = document.querySelector('.split-stage');
const divider = document.querySelector('.split-divider');
let dragging = false;
let rafId = null;
let pctCache = 60;
const clamp = (n, a, b)=> Math.min(Math.max(n, a), b);
const px = (n)=> `${n}px`;
const setPct = (pct) => {
pctCache = pct;
left.style.width = pct + '%';
if (divider) divider.style.left = pct + '%';
const normalizedPct = (pct - 50) / 50;
stage?.style.setProperty('--left-opacity', 1 - Math.abs(normalizedPct) * 0.3);
stage?.style.setProperty('--right-opacity', 1 - Math.abs(normalizedPct) * 0.3);
stage?.style.setProperty('--left-shift', normalizedPct * 0.5);
stage?.style.setProperty('--right-shift', -normalizedPct * 0.5);
stage?.setAttribute('aria-valuenow', Math.round(pct));
};
const handlePointer = (clientX, clientY)=> {
stage?.style.setProperty('--cursor-x', px(clientX));
stage?.style.setProperty('--cursor-y', px(clientY));
const pct = clamp((clientX / stage.clientWidth) * 100, 10, 90);
setPct(pct);
};
const onPointerDown = (e)=>{
dragging = true;
stage.setPointerCapture?.(e.pointerId);
};
const onPointerUp = (e)=>{
dragging = false;
stage.releasePointerCapture?.(e.pointerId);
};
const onPointerMove = (e)=>{
const rect = stage.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
if (!dragging && e.pointerType === 'mouse') {
if (rafId) cancelAnimationFrame(rafId);
rafId = requestAnimationFrame(()=> handlePointer(x, y));
return;
}
if (!dragging) return;
if (rafId) cancelAnimationFrame(rafId);
rafId = requestAnimationFrame(()=> handlePointer(x, y));
};
// Teclado
stage?.addEventListener('keydown', (e) => {
const step = (e.shiftKey ? 10 : 5);
let newVal = pctCache;
if (e.key === 'ArrowLeft') newVal = Math.max(10, pctCache - step);
if (e.key === 'ArrowRight') newVal = Math.min(90, pctCache + step);
if (newVal !== pctCache){
e.preventDefault();
setPct(newVal);
}
});
// Eventos
stage?.addEventListener('pointerdown', onPointerDown);
window.addEventListener('pointerup', onPointerUp);
stage?.addEventListener('pointermove', onPointerMove, { passive: true });
window.addEventListener('resize', ()=> setPct(pctCache));
// Init
window.addEventListener('load', ()=> setPct(60), { once:true });
})();
Transformación Educativa: La IA y Su Efecto en la Educación Superior en Latinoamérica
88
Esta app te permite diseñar y probar agentes de IA que atienden a tus clientes
Agentes de IA para tu e-commerce
367
Un experimento visual con HTML y CSS inspirado en televisores CRT, señales analógicas, glitch y estética retro para presentar recursos,
ElSaltoWeb News
325
MCP Builder IA es una APK Android para generar conectores MCP orientados a negocio. Permite crear proyectos Node.js, definir tools,
MCP Builder IA: APK Android para generar conectores MCP con inteligencia artificial
492