View Transitions

Es una nueva API de navegador diseñada para facilitar animaciones fluidas y transiciones entre vistas o elementos en páginas web.

Esta funcionalidad permite a los desarrolladores crear experiencias más dinámicas y atractivas, como pasar de una galería de imágenes a un detalle ampliado o cambiar entre diferentes secciones de una página, con transiciones suaves entre estados.

¿Cómo funciona?

La API de View Transitions actúa como un puente entre dos estados visuales diferentes de una página web. En lugar de simplemente actualizar el contenido de manera abrupta, permite al navegador animar los cambios de forma fluida.

  1. Estado inicial: La vista actual (por ejemplo, una miniatura de imagen).
  2. Estado final: La vista siguiente (por ejemplo, una imagen ampliada o detalles).
  3. Transición animada: El navegador interpola automáticamente entre ambos estados.

HTML+JS

				
					<fieldset id="gallery" class="hub">
  <div>
    <input type="radio" id="image-1" name="gallery" value="image-1" checked>
    <img decoding="async" src="https://assets.codepen.io/2585/image_fx_a_black_wolf_in_armor_wrecking_a_steampunk_ci.jpg" alt="" />
    <label for="image-1">Cyber Wolf</label>
  </div>

  <div>
    <input type="radio" id="image-2" name="gallery" value="image-2">
    <img decoding="async" src="https://assets.codepen.io/2585/image_fx_cyberpunk_city_scene_with_neon_streaks_of_lig+%283%29.jpg" alt="" />
    <label for="image-2">Flying cars</label>
  </div>

  <div>
    <input type="radio" id="image-3" name="gallery" value="image-3">
    <img decoding="async" src="https://assets.codepen.io/2585/image_fx_cyberpunk_city_scene_with_neon_streaks_of_lig+%282%29.jpg" alt="" />
    <label for="image-3">Flying cars 2</label>
  </div>
  
  <div>
    <input type="radio" id="image-4" name="gallery" value="image-4">
    <img decoding="async" src="https://assets.codepen.io/2585/image_fx_cyberpunk_city_scene_with_neon_streaks_of_lig+%281%29.jpg" alt="" />
    <label for="image-4">Flying cars 3</label>
  </div>
   
  <div>
    <input type="radio" id="image-5" name="gallery" value="image-5">
    <img decoding="async" src="https://assets.codepen.io/2585/image_fx_cyberpunk_city_scene_with_neon_streaks_of_lig+%284%29.jpg" alt="" />
    <label for="image-5">Cyber T-Rex</label>
  </div>
   
  <div>
    <input type="radio" id="image-6" name="gallery" value="image-6">
    <img decoding="async" src="https://assets.codepen.io/2585/image_fx_a_raptor_in_armor_wrecking_a_cyberbunk_city_w.jpg" alt="" />
    <label for="image-6">Cyber Raptor</label>
  </div>
   
  <div>
    <input type="radio" id="image-7" name="gallery" value="image-7">
    <img decoding="async" src="https://assets.codepen.io/2585/image_fx_cyberpunk_city_scene_with_neon_streaks_of_lig.jpg" alt="" />
    <label for="image-7">Cyber freeway</label>
  </div>
</fieldset>
<script>
    
    // watch for radio group input clicks
// if VT is supported, prevent the default behavior
// call VT and manually set checked
document.querySelectorAll('#gallery input').forEach(radio => {
  radio.onclick = e => {
    if (!document.startViewTransition) return;

    e.preventDefault();

    function mutate() {
      // radio group naturally handled unchecking the current one
      e.target.checked = true;
      // reset the zindex so the next item can be on top
      e.target.parentNode.style.zIndex = null;
    }

    // ensures selected item is on top during view transition
    e.target.parentNode.style.zIndex = 2;

    // always mutate, but VT if possible
    document.startViewTransition ?
    document.startViewTransition(() => mutate()) :
    mutate();
  };
});

// function to handle device rotation / page resize
function flipGallery() {
  function mutate(vertical = false) {
    if (document.startViewTransition)
    document.startViewTransition(() =>
    vertical ?
    gallery.classList.add('portrait') :
    gallery.classList.remove('portrait'));
  }

  mutate(window.innerWidth <= 768);
}

// throttled resize observer
// waits for 100ms of no resizing before firing flipGallery()
window.onresize = () => {
  clearTimeout(window.resizeEndTimer);
  window.resizeEndTimer = setTimeout(flipGallery, 100);
};
    
</script>
				
			

CSS

				
					@import "https://unpkg.com/open-props/easings.min.css";

@layer demo.view-transition {
  ::view-transition-group(*) {
    animation-duration: .5s;
    animation-timing-function: var(--ease-5);
  }
  
  .hub > * {
    @media (prefers-reduced-motion: no-preference) {
      &:nth-child(1) {
        view-transition-name: gallery-item-1;
      }
      &:nth-child(2) {
        view-transition-name: gallery-item-2;
      }
      &:nth-child(3) {
        view-transition-name: gallery-item-3;
      }
      &:nth-child(4) {
        view-transition-name: gallery-item-4;
      }
      &:nth-child(5) {
        view-transition-name: gallery-item-5;
      }
      &:nth-child(6) {
        view-transition-name: gallery-item-6;
      }
      &:nth-child(7) {
        view-transition-name: gallery-item-7;
      }
    }
}

@layer demo.layout {
  .hub {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(5, 15vw);
    grid-template-rows: repeat(3, 15vw);
    
    &.portrait {
      grid-template-columns: repeat(3, 20vw);
      grid-template-rows: repeat(5, 20vw);
    }
    
    /* selected promotion */
    > :has(:checked) {
      grid-column: 1 / 4;
      grid-row: 1 / 4;
    }
    
    /* pile the label, input and image */
    > * {
      display: grid;
      
      > * {
        grid-area: 1/1;
      }
      
      > label {
        opacity: 0;
        cursor: pointer;
        -webkit-tap-highlight-color: transparent;
      }
      
      > input {
        border-radius: 0;
        outline-offset: 5px;
        outline-color: deeppink;
        outline-color: color(display-p3 1 0 1);
      } 
    }
  }
}

@layer demo.support {
  * {
    box-sizing: border-box;
    margin: 0;
  }

  html {
    block-size: 100%;
    color-scheme: dark light;
  }

  body {
    min-block-size: 100%;
    font-family: system-ui, sans-serif;


    place-content: center;
  }
  
  fieldset {
    border: none;
    padding: 0;
    margin: 0;
  }
  
  img {
    max-inline-size: 100%;
  }
  
  html {
    view-transition-name: none;
  }
}

.particle-container {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: -1; /* Coloca las partículas detrás del contenido */
  overflow: hidden;
}

.particle {
  position: absolute;
  width: 10px;
  height: 10px;
  background: rgba(255, 255, 255, 0.8); /* Partículas blancas */
  border-radius: 50%;
  animation: moveParticle 5s linear infinite;
  opacity: 0.5;
}

/* Animación para las partículas */
@keyframes moveParticle {
  0% {
    transform: translateY(0) translateX(0);
    opacity: 1;
  }
  100% {
    transform: translateY(100vh) translateX(calc(100vw * -0.5));
    opacity: 0;
  }
}
				
			
COMPARTIR EN:
Facebook
LinkedIn
WhatsApp

Image Accordion Slider with CSS and JS

🚀 Efecto accordion slider 🖼️ que combina imágenes con animaciones suaves y diseño interactivo.💻🔥
COMPARTIR EN:
Facebook
LinkedIn
WhatsApp

¿Qué es View Transitions?

View Transitions es una API moderna del navegador que permite crear transiciones fluidas entre diferentes vistas o estados de una página web.
COMPARTIR EN:
Facebook
LinkedIn
WhatsApp

Creando partículas controladas por audio en Three.js

👉 Con tecnología de Three.js y Web Audio API, ahora el sonido no solo se escucha, ¡se ve en tiempo real! 💻🎶
COMPARTIR EN:
Facebook
LinkedIn
WhatsApp

Looping words with GSAP

CodePen Looping words with GSAP
COMPARTIR EN:
Facebook
LinkedIn
WhatsApp

WordPress con React y Gutenberg

Crear una landing page con React y Gutenberg en WordPress es una combinación poderosa para lograr una experiencia de usuario moderna y un control total sobre el desarrollo.
COMPARTIR EN:
Facebook
LinkedIn
WhatsApp

Fundamentos avanzados de UI

Temario completo del Curso UI