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

ChatKit de OpenAI: Revolucionando la Comunicación Digital

COMPARTIR EN:
Facebook
LinkedIn
WhatsApp

Agentes de IA con LangChain

Agentes de IA con LangChain: arquitectura, seguridad y resultados
COMPARTIR EN:
Facebook
LinkedIn
WhatsApp

Efecto de estrellas detrás de tu ratón

¿Te fascina el cielo estrellado? 🌌🌠 Explora este proyecto «Star Trails with Options» y personaliza la magia del firmamento. 💫🔧
COMPARTIR EN:
Facebook
LinkedIn
WhatsApp

Slider responsivo solo HTML y CSS

Slider totalmente personalizado que hemos creado utilizando solo HTML y CSS.
COMPARTIR EN:
Facebook
LinkedIn
WhatsApp

NBA LEGENDS

Leyendas de la NBA: Quiénes son los GOATs de la Historia
COMPARTIR EN:
Facebook
LinkedIn
WhatsApp

Cómo mejorar la experiencia de usuario (UX) con un diseño web profesional

UI/UX en acción: claves para optimizar tu web y aumentar conversiones