{"schemaVersion":1,"id":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026","title":"CSS Anchor Positioning y Popover API: Implementación de Tooltips Sin JavaScript","description":"Construcción de tooltips, dropdowns y UI flotante enteramente en CSS con la función anchor(), position-try-fallbacks y la Popover API. Estado actual del soporte en navegadores y brechas pendientes en la especificación.","language":"es","datePublished":"2026-01-23","dateModified":null,"contentFormat":"text/markdown","content":"Frontend\n\n# CSS Anchor Positioning y Popover API: Implementación de Tooltips Sin JavaScript\n\n2026-01-238 min lectura\n\nLucio Durán\nEngineering Manager & AI Solutions Architect\n\nTambién disponible en: [English](<https://lucioduran.com/blog/css-anchor-positioning-popover-api-2026>)\n\n## Las Dos Piezas: Anchor Positioning + Popover\n\nSon especificaciones separadas que funcionan bien en conjunto:\n\n**CSS Anchor Positioning** maneja la pregunta de \"¿dónde va el elemento flotante?\". Introduce la función ` anchor() `, la propiedad ` anchor-name `, y ` position-try-fallbacks ` para reposicionamiento automático.\n\n**Popover API** maneja la pregunta de \"¿cómo se comporta el elemento flotante?\". Proporciona renderizado en top-layer (siempre arriba, sin guerras de z-index), light-dismiss (click afuera para cerrar), y semántica de accesibilidad correcta.\n\nEs posible usar cualquiera de las dos de forma independiente, pero juntas reemplazan todo el stack de Floating UI + React Portal + click-outside-handler + manejo de z-index.\n\n## Anchor Positioning: Lo Básico\n\nA continuación se presenta el ejemplo más simple posible, un tooltip posicionado debajo de un botón:\n\n```css\n/* El anchor (elemento trigger) */\n.trigger {\n anchor-name: --my-trigger;\n}\n\n/* El elemento posicionado (tooltip) */\n.tooltip {\n position: fixed;\n position-anchor: --my-trigger;\n\n /* Posicionar la esquina top-left del tooltip en el bottom-center del anchor */\n top: anchor(bottom);\n left: anchor(center);\n translate: -50% 0; /* Centrar horizontalmente */\n\n /* Asegurar que no se desborde del viewport */\n position-try-fallbacks: flip-block;\n}\n```\n\n```html\n<button class=\"trigger\">Hovereame</button>\n<div class=\"tooltip\" popover>¡Soy un tooltip!</div>\n```\n\nLa función ` anchor() ` toma un keyword de lado (` top `, ` right `, ` bottom `, ` left `, ` center `) y devuelve la coordenada correspondiente del elemento anchor. Sin ` getBoundingClientRect() `, sin resize observers, sin scroll listeners.\n\n### La Función anchor() En Profundidad\n\nLa firma de la función es más poderosa de lo que sugiere el ejemplo básico:\n\n```css\n.positioned {\n position: fixed;\n position-anchor: --my-anchor;\n\n /* Básico: posicionar relativo a los bordes del anchor */\n top: anchor(bottom); /* alinear al borde inferior del anchor */\n left: anchor(left); /* alinear al borde izquierdo del anchor */\n right: anchor(right); /* alinear al borde derecho del anchor */\n\n /* Con porcentaje: interpolar entre bordes */\n left: anchor(50%); /* centro del anchor (igual que anchor(center)) */\n top: anchor(25%); /* 25% desde el top del anchor */\n\n /* Calc también funciona */\n top: calc(anchor(bottom) + 8px); /* gap de 8px debajo del anchor */\n left: calc(anchor(center) - 20px); /* offset desde el centro */\n}\n```\n\n### Componente Tooltip del Mundo Real\n\nA continuación se presenta un sistema de tooltips completo con flecha, animación y reposicionamiento automático:\n\n```css\n/* Trigger del tooltip */\n[data-tooltip-anchor] {\n anchor-name: --tooltip-anchor;\n}\n\n/* Contenedor del tooltip */\n.tooltip {\n position: fixed;\n position-anchor: --tooltip-anchor;\n position-visibility: anchors-visible;\n\n /* Posición default: abajo y centrado */\n top: calc(anchor(bottom) + 8px);\n justify-self: anchor-center;\n\n /* Estilos */\n background: var(--tooltip-bg, #1a1a2e);\n color: var(--tooltip-text, #eee);\n padding: 8px 12px;\n border-radius: 6px;\n font-size: 0.875rem;\n max-width: 280px;\n width: max-content;\n filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.15));\n\n /* Animación */\n opacity: 0;\n transform: translateY(-4px);\n transition: opacity 150ms ease, transform 150ms ease;\n\n /* Posiciones fallback */\n position-try-fallbacks:\n --tooltip-above,\n --tooltip-left,\n --tooltip-right;\n}\n\n/* Estado visible */\n.trigger:hover + .tooltip,\n.trigger:focus-visible + .tooltip {\n opacity: 1;\n transform: translateY(0);\n}\n\n/* Flecha */\n.tooltip::before {\n content: '';\n position: absolute;\n bottom: 100%;\n left: 50%;\n translate: -50% 0;\n border: 6px solid transparent;\n border-bottom-color: var(--tooltip-bg, #1a1a2e);\n}\n\n/* Posición fallback: arriba */\n@position-try --tooltip-above {\n bottom: calc(anchor(top) + 8px);\n top: auto;\n justify-self: anchor-center;\n}\n\n/* Posición fallback: izquierda */\n@position-try --tooltip-left {\n right: calc(anchor(left) + 8px);\n top: anchor(center);\n left: auto;\n translate: 0 -50%;\n}\n\n/* Posición fallback: derecha */\n@position-try --tooltip-right {\n left: calc(anchor(right) + 8px);\n top: anchor(center);\n translate: 0 -50%;\n}\n```\n\nCuando el tooltip desbordaría el viewport debajo del botón, el browser automáticamente prueba ` --tooltip-above `, después ` --tooltip-left `, después ` --tooltip-right `. Sin JavaScript. Sin resize observer. Sin scroll handler.\n\n## La Popover API: Capacidades y Comportamiento\n\nLa Popover API no es solo alternar ` display: none `. Provee tres cosas que son genuinamente difíciles de construir correctamente:\n\n### 1. Renderizado en Top Layer\n\nLos elementos con el atributo ` popover ` se renderizan en el top layer del browser, la misma capa usada por ` <dialog> ` y los elementos fullscreen. Esto significa cero problemas de stacking context con z-index. Tu popover siempre se renderiza arriba de todo, incluso si su padre en el DOM tiene ` overflow: hidden ` o un z-index bajo.\n\n```html\n<div style=\"overflow: hidden; position: relative; z-index: 1;\">\n <button popovertarget=\"my-popup\">Abrir</button>\n</div>\n\n<!-- Esto se renderiza en el top layer, sin que le afecte el overflow/z-index del padre -->\n<div id=\"my-popup\" popover>\n ¡Soy libre de la cárcel del z-index!\n</div>\n```\n\n### 2. Light Dismiss\n\n` popover=\"auto\" ` (el default) te da light-dismiss automático. Hacer click en cualquier lugar fuera del popover lo cierra. Presionar Escape lo cierra. Abrir otro popover auto cierra el anterior. Este es el comportamiento que cada librería de dropdowns reimplementa, y el browser lo hace correctamente para todas las modalidades de input (mouse, touch, teclado).\n\n```html\n<!-- Popover auto: light-dismiss habilitado -->\n<button popovertarget=\"dropdown\">Menú</button>\n<div id=\"dropdown\" popover=\"auto\">\n <a href=\"/profile\">Perfil</a>\n <a href=\"/settings\">Configuración</a>\n <a href=\"/logout\">Cerrar sesión</a>\n</div>\n\n<!-- Popover manual: sin light-dismiss, hay que cerrarlo explícitamente -->\n<button popovertarget=\"notification\">Mostrar</button>\n<div id=\"notification\" popover=\"manual\">\n Esto se queda hasta que lo cierres.\n <button popovertarget=\"notification\" popovertargetaction=\"hide\">Cerrar</button>\n</div>\n```\n\n### 3. Accesibilidad Incluida\n\nLa API de popover maneja el focus management y los atributos ARIA automáticamente. Cuando un popover se abre, se hace accesible para tecnologías asistivas. El botón ` popovertarget ` obtiene automáticamente el comportamiento de ` aria-expanded `.\n\n## Construyendo un Menú Dropdown Completo\n\nA continuación se presenta un menú dropdown de grado producción usando ambas APIs juntas:\n\n```html\n<nav class=\"main-nav\">\n <button\n class=\"nav-trigger\"\n popovertarget=\"products-menu\"\n style=\"anchor-name: --products-trigger\"\n >\n Productos ▾\n </button>\n\n <div\n id=\"products-menu\"\n class=\"dropdown-menu\"\n popover=\"auto\"\n style=\"position-anchor: --products-trigger\"\n >\n <a href=\"/products/analytics\" class=\"dropdown-item\">\n <div>\n <strong>Analytics</strong>\n <small>Rastreá el comportamiento de usuarios</small>\n </div>\n </a>\n <a href=\"/products/monitoring\" class=\"dropdown-item\">\n <div>\n <strong>Monitoring</strong>\n <small>Alertas en tiempo real</small>\n </div>\n </a>\n <hr class=\"dropdown-divider\" />\n <a href=\"/products/all\" class=\"dropdown-item\">\n Ver todos los productos →\n </a>\n </div>\n</nav>\n```\n\n```css\n.dropdown-menu {\n position: fixed;\n position-anchor: --products-trigger;\n\n /* Posicionar debajo del trigger, alineado al borde izquierdo */\n top: calc(anchor(bottom) + 4px);\n left: anchor(left);\n\n /* Tamaño */\n min-width: anchor-size(width); /* Al menos tan ancho como el trigger */\n max-width: 320px;\n\n /* Estilos */\n background: white;\n border: 1px solid #e2e2e2;\n border-radius: 8px;\n padding: 4px;\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);\n\n /* Animación */\n opacity: 0;\n transform: translateY(-8px) scale(0.96);\n transition: opacity 200ms ease,\n transform 200ms ease,\n overlay 200ms ease allow-discrete,\n display 200ms ease allow-discrete;\n\n /* Fallback: flipear arriba si no hay lugar abajo */\n position-try-fallbacks: flip-block;\n}\n\n/* Estado abierto */\n.dropdown-menu:popover-open {\n opacity: 1;\n transform: translateY(0) scale(1);\n}\n\n/* Starting style para la animación de entrada */\n@starting-style {\n .dropdown-menu:popover-open {\n opacity: 0;\n transform: translateY(-8px) scale(0.96);\n }\n}\n```\n\nCero JavaScript. El botón alterna el popover. El popover se posiciona solo respecto al botón. Hacer click afuera lo cierra. Si no hay lugar abajo, invierte arriba. La animación de entrada usa ` @starting-style ` para animar correctamente de ` display: none ` a ` display: block `.\n\n## La Función anchor-size()\n\nUna feature subestimada es ` anchor-size() `, que te deja leer las dimensiones de tu elemento anchor:\n\n```css\n.dropdown {\n /* Hacer que el dropdown sea al menos tan ancho como el trigger */\n min-width: anchor-size(width);\n\n /* O matchearlo exacto */\n width: anchor-size(width);\n\n /* También es posible leer el height */\n max-height: calc(100vh - anchor-size(height) - 16px);\n}\n```\n\nEsto es perfecto para dropdowns de autocomplete que deberían coincide conr el ancho del campo de input, o para mega-menús que abarcan el ancho de su item nav trigger.\n\n## Estado del Soporte en Navegadores\n\nDónde estamos a principios de 2026:\n\n| Feature | Chrome | Firefox | Safari |\n| --- | --- | --- | --- |\n| Popover API | 114+ | 125+ | 17+ |\n| ` anchor-name ` / ` position-anchor ` | 125+ | Detrás de flag | En desarrollo |\n| ` anchor() ` function | 125+ | Detrás de flag | En desarrollo |\n| ` position-try-fallbacks ` | 125+ | Detrás de flag | En desarrollo |\n| ` anchor-size() ` | 125+ | Detrás de flag | En desarrollo |\n| ` @position-try ` | 125+ | Detrás de flag | En desarrollo |\n| ` position-visibility ` | 131+ | No | No |\n\nLa Popover API tiene soporte amplio. Anchor positioning es solo Chrome/Edge en producción. Firefox está cerca (detrás de flag desde la 127), y Safari está trabajando activamente.\n\n### Estrategia de Progressive Enhancement\n\n```css\n/* Base: funciona en todos lados */\n.tooltip {\n position: fixed;\n /* Posicionamiento basado en JS como fallback */\n}\n\n/* Mejorado: anchor positioning donde esté soportado */\n@supports (anchor-name: --test) {\n .tooltip {\n position-anchor: --trigger;\n top: calc(anchor(bottom) + 8px);\n justify-self: anchor-center;\n position-try-fallbacks: flip-block;\n }\n}\n```\n\n```javascript\n// Solo cargar Floating UI si anchor positioning no está soportado\nif (!CSS.supports('anchor-name', '--test')) {\n import('floating-ui').then(({ computePosition, flip, offset }) => {\n // Lógica de posicionamiento fallback\n });\n}\n```\n\nAsí, el 70%+ de los usuarios (Chrome/Edge) obtienen la experiencia nativa con cero JavaScript, y el resto recibe el fallback con Floating UI.\n\n## Qué Significa Esto para las Librerías de UI\n\nCada librería de componentes importante implementa alguna forma de posicionamiento de UI flotante. A medida que anchor positioning gane soporte en browsers, estas librerías lo van a adoptar progresivamente. Algunas ya tienen flags experimentales. El estado final es que la lógica de posicionamiento se mueve del bundle de JavaScript al motor del browser, reduciendo tanto el tamaño del bundle como la computación en runtime.\n\nPara proyectos nuevos, si solo se apunta a browsers Chromium (apps Electron, herramientas internas, extensiones de Chrome), es posible usar anchor positioning hoy con cero fallback necesario. Para sitios web públicos, el approach de progressive enhancement mostrado arriba es el camino pragmático.\n\nLa plataforma web finalmente se está poniendo al día con lo que los frameworks de UI nativos hicieron durante décadas, dejar que el motor de layout maneje el posicionamiento de elementos. Tardó más de lo necesario, pero la capacidad ya está disponible.\n\n## Preguntas frecuentes\n\n### ¿Qué es CSS Anchor Positioning?\n\nCSS Anchor Positioning es una nueva especificación CSS que permite posicionar un elemento relativo a otro elemento (el anchor) usando la función anchor(), sin JavaScript. Maneja overflow, límites del viewport y posiciones fallback de forma nativa.\n\n### ¿Qué es la Popover API?\n\nLa Popover API es una API nativa del browser que provee renderizado en top-layer, comportamiento de light-dismiss y semántica de accesibilidad para elementos flotantes como tooltips, menús y diálogos, todo sin JavaScript.\n\n### ¿Puedo usar anchor positioning en producción hoy?\n\nChrome 125+ y Edge 125+ tienen soporte completo. Firefox tiene soporte parcial detrás de flags. El soporte de Safari está en desarrollo. Para producción, utilizar progressive enhancement con un fallback en JavaScript para navegadores no soportados.\n\n### ¿Esto reemplaza a Floating UI / Popper.js?\n\nEventualmente, sí. Para navegadores que lo soportan, CSS Anchor Positioning maneja todo lo que hace Floating UI, posicionamiento, flipping, shifting, de forma nativa. Sin embargo, se necesita una estrategia de fallback hasta que Safari implemente soporte completo.\n\n## Tips\n\n1. **Tip:** La propiedad ` anchor-name ` debe ser única por documento. Si dos elementos comparten el mismo nombre de anchor, prevalece el último en orden del DOM. Utilizar naming estilo BEM como ` --anchor-nav-dropdown ` para evitar colisiones.\n2. **Tip:** Configurar siempre ` position-try-fallbacks ` al usar anchor positioning. Sin esta propiedad, el tooltip se renderiza fuera de la pantalla sin aviso. Comenzar con ` position-try-fallbacks: flip-block, flip-inline ` como valor predeterminado razonable.\n3. **Tip:** El ` popover=auto ` de la Popover API proporciona light-dismiss automático (click afuera para cerrar) y renderizado en top-layer. No es necesario reimplementar esto con ` addEventListener('click', outsideHandler) `, el navegador lo maneja de forma más confiable.\n4. **Tip:** Probar anchor positioning con ` position-visibility: anchors-visible ` para ocultar automáticamente el elemento posicionado cuando el anchor sale de la vista por scroll. Esto reemplaza las soluciones basadas en IntersectionObserver para tooltips sensibles al scroll.\n\n- css\n- anchor-positioning\n- popover-api\n- frontend\n- tooltips\n- dropdowns\n- browser-apis\n\n[Volver al Blog](<https://lucioduran.com/es/blog>)","headings":[{"level":1,"text":"CSS Anchor Positioning y Popover API: Implementación de Tooltips Sin JavaScript","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#title"},{"level":2,"text":"Las Dos Piezas: Anchor Positioning + Popover","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#las-dos-piezas-anchor-positioning-popover"},{"level":2,"text":"Anchor Positioning: Lo Básico","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#anchor-positioning-lo-bsico"},{"level":3,"text":"La Función anchor() En Profundidad","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#la-funcin-anchor-en-profundidad"},{"level":3,"text":"Componente Tooltip del Mundo Real","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#componente-tooltip-del-mundo-real"},{"level":2,"text":"La Popover API: Capacidades y Comportamiento","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#la-popover-api-capacidades-y-comportamiento"},{"level":3,"text":"1. Renderizado en Top Layer","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#1-renderizado-en-top-layer"},{"level":3,"text":"2. Light Dismiss","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#2-light-dismiss"},{"level":3,"text":"3. Accesibilidad Incluida","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#3-accesibilidad-incluida"},{"level":2,"text":"Construyendo un Menú Dropdown Completo","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#construyendo-un-men-dropdown-completo"},{"level":2,"text":"La Función anchor-size()","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#la-funcin-anchor-size"},{"level":2,"text":"Estado del Soporte en Navegadores","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#estado-del-soporte-en-navegadores"},{"level":3,"text":"Estrategia de Progressive Enhancement","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#estrategia-de-progressive-enhancement"},{"level":2,"text":"Qué Significa Esto para las Librerías de UI","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#qu-significa-esto-para-las-libreras-de-ui"},{"level":2,"text":"Preguntas frecuentes","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#questions"},{"level":3,"text":"¿Qué es CSS Anchor Positioning?","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#question-1"},{"level":3,"text":"¿Qué es la Popover API?","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#question-2"},{"level":3,"text":"¿Puedo usar anchor positioning en producción hoy?","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#question-3"},{"level":3,"text":"¿Esto reemplaza a Floating UI / Popper.js?","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#question-4"},{"level":2,"text":"Tips","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#article-tips"}],"sections":[{"heading":"CSS Anchor Positioning y Popover API: Implementación de Tooltips Sin JavaScript","level":1,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026","content":"Frontend"},{"heading":"CSS Anchor Positioning y Popover API: Implementación de Tooltips Sin JavaScript","level":1,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#title","content":"2026-01-238 min lectura\n\nLucio Durán\nEngineering Manager & AI Solutions Architect\n\nTambién disponible en: [English](<https://lucioduran.com/blog/css-anchor-positioning-popover-api-2026>)"},{"heading":"Las Dos Piezas: Anchor Positioning + Popover","level":2,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#las-dos-piezas-anchor-positioning-popover","content":"Son especificaciones separadas que funcionan bien en conjunto:\n\n**CSS Anchor Positioning** maneja la pregunta de \"¿dónde va el elemento flotante?\". Introduce la función ` anchor() `, la propiedad ` anchor-name `, y ` position-try-fallbacks ` para reposicionamiento automático.\n\n**Popover API** maneja la pregunta de \"¿cómo se comporta el elemento flotante?\". Proporciona renderizado en top-layer (siempre arriba, sin guerras de z-index), light-dismiss (click afuera para cerrar), y semántica de accesibilidad correcta.\n\nEs posible usar cualquiera de las dos de forma independiente, pero juntas reemplazan todo el stack de Floating UI + React Portal + click-outside-handler + manejo de z-index."},{"heading":"Anchor Positioning: Lo Básico","level":2,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#anchor-positioning-lo-bsico","content":"A continuación se presenta el ejemplo más simple posible, un tooltip posicionado debajo de un botón:\n\n```css\n/* El anchor (elemento trigger) */\n.trigger {\n anchor-name: --my-trigger;\n}\n\n/* El elemento posicionado (tooltip) */\n.tooltip {\n position: fixed;\n position-anchor: --my-trigger;\n\n /* Posicionar la esquina top-left del tooltip en el bottom-center del anchor */\n top: anchor(bottom);\n left: anchor(center);\n translate: -50% 0; /* Centrar horizontalmente */\n\n /* Asegurar que no se desborde del viewport */\n position-try-fallbacks: flip-block;\n}\n```\n\n```html\n<button class=\"trigger\">Hovereame</button>\n<div class=\"tooltip\" popover>¡Soy un tooltip!</div>\n```\n\nLa función ` anchor() ` toma un keyword de lado (` top `, ` right `, ` bottom `, ` left `, ` center `) y devuelve la coordenada correspondiente del elemento anchor. Sin ` getBoundingClientRect() `, sin resize observers, sin scroll listeners."},{"heading":"La Función anchor() En Profundidad","level":3,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#la-funcin-anchor-en-profundidad","content":"La firma de la función es más poderosa de lo que sugiere el ejemplo básico:\n\n```css\n.positioned {\n position: fixed;\n position-anchor: --my-anchor;\n\n /* Básico: posicionar relativo a los bordes del anchor */\n top: anchor(bottom); /* alinear al borde inferior del anchor */\n left: anchor(left); /* alinear al borde izquierdo del anchor */\n right: anchor(right); /* alinear al borde derecho del anchor */\n\n /* Con porcentaje: interpolar entre bordes */\n left: anchor(50%); /* centro del anchor (igual que anchor(center)) */\n top: anchor(25%); /* 25% desde el top del anchor */\n\n /* Calc también funciona */\n top: calc(anchor(bottom) + 8px); /* gap de 8px debajo del anchor */\n left: calc(anchor(center) - 20px); /* offset desde el centro */\n}\n```"},{"heading":"Componente Tooltip del Mundo Real","level":3,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#componente-tooltip-del-mundo-real","content":"A continuación se presenta un sistema de tooltips completo con flecha, animación y reposicionamiento automático:\n\n```css\n/* Trigger del tooltip */\n[data-tooltip-anchor] {\n anchor-name: --tooltip-anchor;\n}\n\n/* Contenedor del tooltip */\n.tooltip {\n position: fixed;\n position-anchor: --tooltip-anchor;\n position-visibility: anchors-visible;\n\n /* Posición default: abajo y centrado */\n top: calc(anchor(bottom) + 8px);\n justify-self: anchor-center;\n\n /* Estilos */\n background: var(--tooltip-bg, #1a1a2e);\n color: var(--tooltip-text, #eee);\n padding: 8px 12px;\n border-radius: 6px;\n font-size: 0.875rem;\n max-width: 280px;\n width: max-content;\n filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.15));\n\n /* Animación */\n opacity: 0;\n transform: translateY(-4px);\n transition: opacity 150ms ease, transform 150ms ease;\n\n /* Posiciones fallback */\n position-try-fallbacks:\n --tooltip-above,\n --tooltip-left,\n --tooltip-right;\n}\n\n/* Estado visible */\n.trigger:hover + .tooltip,\n.trigger:focus-visible + .tooltip {\n opacity: 1;\n transform: translateY(0);\n}\n\n/* Flecha */\n.tooltip::before {\n content: '';\n position: absolute;\n bottom: 100%;\n left: 50%;\n translate: -50% 0;\n border: 6px solid transparent;\n border-bottom-color: var(--tooltip-bg, #1a1a2e);\n}\n\n/* Posición fallback: arriba */\n@position-try --tooltip-above {\n bottom: calc(anchor(top) + 8px);\n top: auto;\n justify-self: anchor-center;\n}\n\n/* Posición fallback: izquierda */\n@position-try --tooltip-left {\n right: calc(anchor(left) + 8px);\n top: anchor(center);\n left: auto;\n translate: 0 -50%;\n}\n\n/* Posición fallback: derecha */\n@position-try --tooltip-right {\n left: calc(anchor(right) + 8px);\n top: anchor(center);\n translate: 0 -50%;\n}\n```\n\nCuando el tooltip desbordaría el viewport debajo del botón, el browser automáticamente prueba ` --tooltip-above `, después ` --tooltip-left `, después ` --tooltip-right `. Sin JavaScript. Sin resize observer. Sin scroll handler."},{"heading":"La Popover API: Capacidades y Comportamiento","level":2,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#la-popover-api-capacidades-y-comportamiento","content":"La Popover API no es solo alternar ` display: none `. Provee tres cosas que son genuinamente difíciles de construir correctamente:"},{"heading":"1. Renderizado en Top Layer","level":3,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#1-renderizado-en-top-layer","content":"Los elementos con el atributo ` popover ` se renderizan en el top layer del browser, la misma capa usada por ` <dialog> ` y los elementos fullscreen. Esto significa cero problemas de stacking context con z-index. Tu popover siempre se renderiza arriba de todo, incluso si su padre en el DOM tiene ` overflow: hidden ` o un z-index bajo.\n\n```html\n<div style=\"overflow: hidden; position: relative; z-index: 1;\">\n <button popovertarget=\"my-popup\">Abrir</button>\n</div>\n\n<!-- Esto se renderiza en el top layer, sin que le afecte el overflow/z-index del padre -->\n<div id=\"my-popup\" popover>\n ¡Soy libre de la cárcel del z-index!\n</div>\n```"},{"heading":"2. Light Dismiss","level":3,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#2-light-dismiss","content":"` popover=\"auto\" ` (el default) te da light-dismiss automático. Hacer click en cualquier lugar fuera del popover lo cierra. Presionar Escape lo cierra. Abrir otro popover auto cierra el anterior. Este es el comportamiento que cada librería de dropdowns reimplementa, y el browser lo hace correctamente para todas las modalidades de input (mouse, touch, teclado).\n\n```html\n<!-- Popover auto: light-dismiss habilitado -->\n<button popovertarget=\"dropdown\">Menú</button>\n<div id=\"dropdown\" popover=\"auto\">\n <a href=\"/profile\">Perfil</a>\n <a href=\"/settings\">Configuración</a>\n <a href=\"/logout\">Cerrar sesión</a>\n</div>\n\n<!-- Popover manual: sin light-dismiss, hay que cerrarlo explícitamente -->\n<button popovertarget=\"notification\">Mostrar</button>\n<div id=\"notification\" popover=\"manual\">\n Esto se queda hasta que lo cierres.\n <button popovertarget=\"notification\" popovertargetaction=\"hide\">Cerrar</button>\n</div>\n```"},{"heading":"3. Accesibilidad Incluida","level":3,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#3-accesibilidad-incluida","content":"La API de popover maneja el focus management y los atributos ARIA automáticamente. Cuando un popover se abre, se hace accesible para tecnologías asistivas. El botón ` popovertarget ` obtiene automáticamente el comportamiento de ` aria-expanded `."},{"heading":"Construyendo un Menú Dropdown Completo","level":2,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#construyendo-un-men-dropdown-completo","content":"A continuación se presenta un menú dropdown de grado producción usando ambas APIs juntas:\n\n```html\n<nav class=\"main-nav\">\n <button\n class=\"nav-trigger\"\n popovertarget=\"products-menu\"\n style=\"anchor-name: --products-trigger\"\n >\n Productos ▾\n </button>\n\n <div\n id=\"products-menu\"\n class=\"dropdown-menu\"\n popover=\"auto\"\n style=\"position-anchor: --products-trigger\"\n >\n <a href=\"/products/analytics\" class=\"dropdown-item\">\n <div>\n <strong>Analytics</strong>\n <small>Rastreá el comportamiento de usuarios</small>\n </div>\n </a>\n <a href=\"/products/monitoring\" class=\"dropdown-item\">\n <div>\n <strong>Monitoring</strong>\n <small>Alertas en tiempo real</small>\n </div>\n </a>\n <hr class=\"dropdown-divider\" />\n <a href=\"/products/all\" class=\"dropdown-item\">\n Ver todos los productos →\n </a>\n </div>\n</nav>\n```\n\n```css\n.dropdown-menu {\n position: fixed;\n position-anchor: --products-trigger;\n\n /* Posicionar debajo del trigger, alineado al borde izquierdo */\n top: calc(anchor(bottom) + 4px);\n left: anchor(left);\n\n /* Tamaño */\n min-width: anchor-size(width); /* Al menos tan ancho como el trigger */\n max-width: 320px;\n\n /* Estilos */\n background: white;\n border: 1px solid #e2e2e2;\n border-radius: 8px;\n padding: 4px;\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);\n\n /* Animación */\n opacity: 0;\n transform: translateY(-8px) scale(0.96);\n transition: opacity 200ms ease,\n transform 200ms ease,\n overlay 200ms ease allow-discrete,\n display 200ms ease allow-discrete;\n\n /* Fallback: flipear arriba si no hay lugar abajo */\n position-try-fallbacks: flip-block;\n}\n\n/* Estado abierto */\n.dropdown-menu:popover-open {\n opacity: 1;\n transform: translateY(0) scale(1);\n}\n\n/* Starting style para la animación de entrada */\n@starting-style {\n .dropdown-menu:popover-open {\n opacity: 0;\n transform: translateY(-8px) scale(0.96);\n }\n}\n```\n\nCero JavaScript. El botón alterna el popover. El popover se posiciona solo respecto al botón. Hacer click afuera lo cierra. Si no hay lugar abajo, invierte arriba. La animación de entrada usa ` @starting-style ` para animar correctamente de ` display: none ` a ` display: block `."},{"heading":"La Función anchor-size()","level":2,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#la-funcin-anchor-size","content":"Una feature subestimada es ` anchor-size() `, que te deja leer las dimensiones de tu elemento anchor:\n\n```css\n.dropdown {\n /* Hacer que el dropdown sea al menos tan ancho como el trigger */\n min-width: anchor-size(width);\n\n /* O matchearlo exacto */\n width: anchor-size(width);\n\n /* También es posible leer el height */\n max-height: calc(100vh - anchor-size(height) - 16px);\n}\n```\n\nEsto es perfecto para dropdowns de autocomplete que deberían coincide conr el ancho del campo de input, o para mega-menús que abarcan el ancho de su item nav trigger."},{"heading":"Estado del Soporte en Navegadores","level":2,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#estado-del-soporte-en-navegadores","content":"Dónde estamos a principios de 2026:\n\n| Feature | Chrome | Firefox | Safari |\n| --- | --- | --- | --- |\n| Popover API | 114+ | 125+ | 17+ |\n| ` anchor-name ` / ` position-anchor ` | 125+ | Detrás de flag | En desarrollo |\n| ` anchor() ` function | 125+ | Detrás de flag | En desarrollo |\n| ` position-try-fallbacks ` | 125+ | Detrás de flag | En desarrollo |\n| ` anchor-size() ` | 125+ | Detrás de flag | En desarrollo |\n| ` @position-try ` | 125+ | Detrás de flag | En desarrollo |\n| ` position-visibility ` | 131+ | No | No |\n\nLa Popover API tiene soporte amplio. Anchor positioning es solo Chrome/Edge en producción. Firefox está cerca (detrás de flag desde la 127), y Safari está trabajando activamente."},{"heading":"Estrategia de Progressive Enhancement","level":3,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#estrategia-de-progressive-enhancement","content":"```css\n/* Base: funciona en todos lados */\n.tooltip {\n position: fixed;\n /* Posicionamiento basado en JS como fallback */\n}\n\n/* Mejorado: anchor positioning donde esté soportado */\n@supports (anchor-name: --test) {\n .tooltip {\n position-anchor: --trigger;\n top: calc(anchor(bottom) + 8px);\n justify-self: anchor-center;\n position-try-fallbacks: flip-block;\n }\n}\n```\n\n```javascript\n// Solo cargar Floating UI si anchor positioning no está soportado\nif (!CSS.supports('anchor-name', '--test')) {\n import('floating-ui').then(({ computePosition, flip, offset }) => {\n // Lógica de posicionamiento fallback\n });\n}\n```\n\nAsí, el 70%+ de los usuarios (Chrome/Edge) obtienen la experiencia nativa con cero JavaScript, y el resto recibe el fallback con Floating UI."},{"heading":"Qué Significa Esto para las Librerías de UI","level":2,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#qu-significa-esto-para-las-libreras-de-ui","content":"Cada librería de componentes importante implementa alguna forma de posicionamiento de UI flotante. A medida que anchor positioning gane soporte en browsers, estas librerías lo van a adoptar progresivamente. Algunas ya tienen flags experimentales. El estado final es que la lógica de posicionamiento se mueve del bundle de JavaScript al motor del browser, reduciendo tanto el tamaño del bundle como la computación en runtime.\n\nPara proyectos nuevos, si solo se apunta a browsers Chromium (apps Electron, herramientas internas, extensiones de Chrome), es posible usar anchor positioning hoy con cero fallback necesario. Para sitios web públicos, el approach de progressive enhancement mostrado arriba es el camino pragmático.\n\nLa plataforma web finalmente se está poniendo al día con lo que los frameworks de UI nativos hicieron durante décadas, dejar que el motor de layout maneje el posicionamiento de elementos. Tardó más de lo necesario, pero la capacidad ya está disponible."},{"heading":"Preguntas frecuentes","level":2,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#questions","content":""},{"heading":"¿Qué es CSS Anchor Positioning?","level":3,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#question-1","content":"CSS Anchor Positioning es una nueva especificación CSS que permite posicionar un elemento relativo a otro elemento (el anchor) usando la función anchor(), sin JavaScript. Maneja overflow, límites del viewport y posiciones fallback de forma nativa."},{"heading":"¿Qué es la Popover API?","level":3,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#question-2","content":"La Popover API es una API nativa del browser que provee renderizado en top-layer, comportamiento de light-dismiss y semántica de accesibilidad para elementos flotantes como tooltips, menús y diálogos, todo sin JavaScript."},{"heading":"¿Puedo usar anchor positioning en producción hoy?","level":3,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#question-3","content":"Chrome 125+ y Edge 125+ tienen soporte completo. Firefox tiene soporte parcial detrás de flags. El soporte de Safari está en desarrollo. Para producción, utilizar progressive enhancement con un fallback en JavaScript para navegadores no soportados."},{"heading":"¿Esto reemplaza a Floating UI / Popper.js?","level":3,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#question-4","content":"Eventualmente, sí. Para navegadores que lo soportan, CSS Anchor Positioning maneja todo lo que hace Floating UI, posicionamiento, flipping, shifting, de forma nativa. Sin embargo, se necesita una estrategia de fallback hasta que Safari implemente soporte completo."},{"heading":"Tips","level":2,"url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#article-tips","content":"1. **Tip:** La propiedad ` anchor-name ` debe ser única por documento. Si dos elementos comparten el mismo nombre de anchor, prevalece el último en orden del DOM. Utilizar naming estilo BEM como ` --anchor-nav-dropdown ` para evitar colisiones.\n2. **Tip:** Configurar siempre ` position-try-fallbacks ` al usar anchor positioning. Sin esta propiedad, el tooltip se renderiza fuera de la pantalla sin aviso. Comenzar con ` position-try-fallbacks: flip-block, flip-inline ` como valor predeterminado razonable.\n3. **Tip:** El ` popover=auto ` de la Popover API proporciona light-dismiss automático (click afuera para cerrar) y renderizado en top-layer. No es necesario reimplementar esto con ` addEventListener('click', outsideHandler) `, el navegador lo maneja de forma más confiable.\n4. **Tip:** Probar anchor positioning con ` position-visibility: anchors-visible ` para ocultar automáticamente el elemento posicionado cuando el anchor sale de la vista por scroll. Esto reemplaza las soluciones basadas en IntersectionObserver para tooltips sensibles al scroll.\n\n- css\n- anchor-positioning\n- popover-api\n- frontend\n- tooltips\n- dropdowns\n- browser-apis\n\n[Volver al Blog](<https://lucioduran.com/es/blog>)"}],"links":[{"text":"English","url":"https://lucioduran.com/blog/css-anchor-positioning-popover-api-2026"},{"text":"Volver al Blog","url":"https://lucioduran.com/es/blog"}],"structuredData":[{"@context":"https://schema.org","@graph":[{"@type":"BlogPosting","@id":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026#article","mainEntityOfPage":{"@type":"WebPage","@id":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026"},"headline":"CSS Anchor Positioning y Popover API: Implementación de Tooltips Sin JavaScript","description":"Construcción de tooltips, dropdowns y UI flotante enteramente en CSS con la función anchor(), position-try-fallbacks y la Popover API. Estado actual del soporte en navegadores y brechas pendientes en la especificación.","datePublished":"2026-01-23","author":{"@type":"Person","@id":"https://lucioduran.com/#person","name":"Lucio Durán","url":"https://lucioduran.com"},"publisher":{"@type":"Person","@id":"https://lucioduran.com/#person","name":"Lucio Durán","url":"https://lucioduran.com"},"image":"https://statics.lucioduran.com/images/lucioduran-social-card.jpg","url":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026","inLanguage":"es","isPartOf":{"@id":"https://lucioduran.com/blog#blog"},"articleSection":"Frontend","keywords":"css, anchor-positioning, popover-api, frontend, tooltips, dropdowns, browser-apis","wordCount":1501,"timeRequired":"PT8M","workTranslation":[{"@type":"BlogPosting","inLanguage":"en","url":"https://lucioduran.com/blog/css-anchor-positioning-popover-api-2026"}]},{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Inicio","item":"https://lucioduran.com/"},{"@type":"ListItem","position":2,"name":"Blog","item":"https://lucioduran.com/es/blog"},{"@type":"ListItem","position":3,"name":"CSS Anchor Positioning y Popover API: Implementación de Tooltips Sin JavaScript","item":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026"}]},{"@type":"FAQPage","mainEntity":[{"@type":"Question","name":"¿Qué es CSS Anchor Positioning?","acceptedAnswer":{"@type":"Answer","text":"CSS Anchor Positioning es una nueva especificación CSS que permite posicionar un elemento relativo a otro elemento (el anchor) usando la función anchor(), sin JavaScript. Maneja overflow, límites del viewport y posiciones fallback de forma nativa."}},{"@type":"Question","name":"¿Qué es la Popover API?","acceptedAnswer":{"@type":"Answer","text":"La Popover API es una API nativa del browser que provee renderizado en top-layer, comportamiento de light-dismiss y semántica de accesibilidad para elementos flotantes como tooltips, menús y diálogos, todo sin JavaScript."}},{"@type":"Question","name":"¿Puedo usar anchor positioning en producción hoy?","acceptedAnswer":{"@type":"Answer","text":"Chrome 125+ y Edge 125+ tienen soporte completo. Firefox tiene soporte parcial detrás de flags. El soporte de Safari está en desarrollo. Para producción, utilizar progressive enhancement con un fallback en JavaScript para navegadores no soportados."}},{"@type":"Question","name":"¿Esto reemplaza a Floating UI / Popper.js?","acceptedAnswer":{"@type":"Answer","text":"Eventualmente, sí. Para navegadores que lo soportan, CSS Anchor Positioning maneja todo lo que hace Floating UI, posicionamiento, flipping, shifting, de forma nativa. Sin embargo, se necesita una estrategia de fallback hasta que Safari implemente soporte completo."}}]}]}],"contentHash":"2823dbfcd864bd7fb420cd3c82ab644f0b80a8260969817092ba72dfb4cb5d60","provenance":{"method":"Deterministic serialization of the server-rendered main element","source":"https://lucioduran.com/es/blog/css-anchor-positioning-popover-api-2026","hashAlgorithm":"sha256","hashScope":"JSON document fields before contentHash and provenance","sourceHTMLBytes":74317,"contentBytes":14594}}
