Cómo utilizar media queries internas en imágenes SVG

Las imágenes SVG son una herramienta muy popular para la creación de gráficos y visualizaciones en la web. Con el uso de media queries internas, es posible ajustar el aspecto de una imagen SVG en función del tamaño de la pantalla del usuario. En este artículo, exploraremos cómo utilizar media queries internas en imágenes SVG.

En primer lugar, es importante entender qué son las media queries internas. En términos simples, una media query es un fragmento de código CSS que permite ajustar el aspecto de un elemento en función de una condición. Las media queries internas son aquellas que se aplican dentro del código SVG, en lugar de en un archivo CSS separado. Esto significa que es posible ajustar la apariencia de una imagen SVG en función del tamaño de la pantalla del usuario.

Pros

  1. Flexibilidad: El uso de media queries internas permite que las imágenes SVG se ajusten de forma automática a diferentes tamaños de pantalla. Esto puede mejorar la experiencia del usuario y hacer que las imágenes sean más accesibles.
  2. Mejor rendimiento: Al utilizar media queries internas, se pueden reducir las descargas innecesarias de recursos en dispositivos móviles. Esto puede mejorar el rendimiento general de la página y reducir los tiempos de carga.
  3. Diseño adaptable: Los medios queries internos permiten un diseño adaptable que se adapta a diferentes resoluciones y tamaños de pantalla. Esto puede ayudar a mejorar la calidad de las imágenes SVG en diferentes dispositivos.

Contras

  1. Curva de aprendizaje: El uso de media queries internas en imágenes SVG puede requerir un poco de aprendizaje, especialmente para aquellos que no están familiarizados con CSS. Es posible que se requiera una inversión de tiempo para aprender cómo utilizarlas de manera efectiva.
  2. Posibles errores: Si no se utilizan correctamente, las media queries internas pueden causar errores en el diseño de las imágenes SVG. Por lo tanto, es importante tener cuidado al escribir y probar el código.
  3. Compatibilidad: Es posible que las media queries internas no sean compatibles con todas las versiones de los navegadores, lo que podría causar problemas de visualización para algunos usuarios.

Ejemplo

Para utilizar media queries internas en una imagen SVG, primero debe definir las reglas de estilo dentro del elemento <style> de su documento SVG. Por ejemplo, para cambiar el color de fondo de un rectángulo en función del tamaño de pantalla, puede utilizar la siguiente media query interna:


<svg>
  <style>
   @media (max-width: 600px) {
      rect {
        fill: blue;
      }
   }
   @media (min-width: 601px) {
      rect {
        fill: red;
      }
    }
  </style>
  <rect x="50" y="50" width="100" height="100"></rect>
</svg>

En este ejemplo, se definen dos media queries internas: una para pantallas de 600 píxeles o menos y otra para pantallas de más de 600 píxeles. En cada una de las media queries, se define un estilo diferente para el rectángulo. En el primer caso, el rectángulo tendrá un color de relleno azul, mientras que en el segundo caso, tendrá un color de relleno rojo.

Es importante tener en cuenta que las media queries internas en SVG funcionan de la misma manera que las media queries en CSS. Por lo tanto, puede utilizar las mismas condiciones, como la anchura de la pantalla o la relación de aspecto, para ajustar la apariencia de su imagen SVG.

En resumen, utilizar media queries internas en imágenes SVG puede ser una forma muy útil de mejorar la experiencia del usuario y hacer que las imágenes sean más adaptables a diferentes dispositivos. Al igual que con cualquier técnica de diseño web, es importante tener en cuenta los posibles contras, como la curva de aprendizaje y la compatibilidad del navegador. Si se utilizan de manera efectiva, las media queries internas pueden ser una excelente manera de mejorar el rendimiento y la calidad de las imágenes SVG en la web.

React Router Hash Link: cómo crear enlaces ancla en React

Crear enlaces ancla en una página web parece algo muy sencillo cuando trabajamos con HTML tradicional. Usamos un enlace con #, añadimos un id a una sección y el navegador se encarga de llevarnos directamente hasta ese punto de la página.

Sin embargo, cuando desarrollamos una aplicación con React y usamos React Router para gestionar la navegación, ese comportamiento puede no ser tan directo. En una SPA, es decir, una aplicación de una sola página, las rutas no funcionan exactamente igual que en una web clásica. El contenido se renderiza desde JavaScript, las páginas no siempre se recargan y el navegador puede no desplazarse automáticamente hasta la sección indicada.

Aquí es donde entra en juego React Router Hash Link, una librería muy práctica para crear enlaces ancla en React cuando trabajamos con React Router. Gracias a su componente HashLink, podemos navegar hacia una ruta concreta y, además, desplazar la vista hasta una sección específica marcada con un id.

En este artículo veremos qué son los enlaces ancla, por qué pueden dar problemas en proyectos con React Router, cómo instalar y usar React Router Hash Link, cómo aplicar smooth scroll y qué buenas prácticas conviene seguir para mejorar la experiencia de usuario en proyectos de desarrollo frontend.

Qué son los enlaces ancla

Los enlaces ancla son enlaces que permiten llevar al usuario directamente a una sección concreta dentro de una misma página. En lugar de cargar una URL completamente nueva, el navegador busca un elemento con un id determinado y desplaza la vista hasta él.

Un ejemplo básico en HTML sería este:

<a href="#contacto">Ir a contacto</a>

<section id="contacto">
  <h2>Contacto</h2>
</section>

Cuando el usuario hace clic en el enlace, el navegador busca el elemento con id="contacto" y hace scroll hasta esa sección.

Este tipo de navegación es muy habitual en páginas largas, landings, portfolios, artículos extensos, páginas de documentación, menús internos y secciones de preguntas frecuentes. También resulta muy útil cuando queremos crear una experiencia de navegación más fluida y evitar que la persona tenga que hacer scroll manualmente hasta encontrar la información que busca.

Los enlaces ancla no son solo un recurso técnico. Bien utilizados, ayudan a ordenar mejor el contenido, reducen la fricción y hacen que la interfaz sea más cómoda de usar.

Si estás trabajando la parte visual de una interfaz, este tipo de detalle conecta muy bien con otros recursos de movimiento y transición. Por ejemplo, en esta guía sobre animaciones CSS explico cómo usar el movimiento para reforzar la experiencia sin sobrecargar la interfaz.

Por qué los enlaces ancla pueden fallar con React Router

En una web tradicional, el navegador gestiona los enlaces ancla de forma nativa. Pero en una aplicación desarrollada con React, especialmente si usamos React Router, la navegación se controla desde el lado del cliente.

Normalmente, para movernos entre rutas usamos componentes como Link o NavLink:

import { Link } from "react-router-dom";

<Link to="/contacto">Contacto</Link>

Este enlace no recarga la página completa. React Router intercepta la navegación y renderiza el componente correspondiente según la ruta.

El problema aparece cuando intentamos usar un enlace con fragmento, por ejemplo:

<Link to="/#servicios">Servicios</Link>

En teoría, este enlace debería llevarnos a la ruta principal y desplazarnos hasta el elemento con id="servicios". Pero, en la práctica, puede no funcionar como esperamos.

Esto puede ocurrir por varios motivos:

  • El contenido se renderiza después del cambio de ruta.
  • El elemento de destino todavía no existe en el DOM.
  • React Router gestiona la navegación sin que el navegador ejecute el comportamiento clásico del hash.
  • La aplicación tiene una cabecera fija que tapa la sección de destino.
  • El scroll se produce antes de que React haya terminado de pintar el contenido.

Por eso, cuando queremos crear enlaces ancla en React de forma fiable, una solución muy cómoda es usar React Router Hash Link.

React Router Hash Link es una librería que extiende el comportamiento de los enlaces de React Router para permitir la navegación hacia secciones concretas dentro de una página.

Su componente principal es HashLink.

En lugar de usar un Link tradicional:

<Link to="/#contacto">Contacto</Link>

usamos:

<HashLink to="/#contacto">Contacto</HashLink>

La diferencia es que HashLink se encarga de encontrar el elemento correspondiente y desplazar la vista hasta él.

Esto resulta especialmente útil en proyectos donde tenemos una estructura como esta:

  • Una landing creada con React.
  • Un menú superior con enlaces a distintas secciones.
  • Un portfolio con bloques como servicios, proyectos y contacto.
  • Una página de documentación técnica.
  • Un artículo largo con índice interno.
  • Un botón de llamada a la acción que lleva directamente a un formulario.

En todos estos casos, HashLink ayuda a mejorar la navegación interna sin tener que escribir lógica manual con JavaScript.

Para instalar la librería, puedes usar npm:

npm install react-router-hash-link

O yarn:

yarn add react-router-hash-link

Antes de usarla, asegúrate de tener instalado y configurado react-router-dom, ya que React Router Hash Link trabaja sobre React Router.

Una estructura básica de aplicación podría ser esta:

import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import Navbar from "./components/Navbar";

function App() {
  return (
    <BrowserRouter>
      <Navbar />

      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/sobre-mi" element={<About />} />
      </Routes>
    </BrowserRouter>
  );
}

export default App;

En este ejemplo, la aplicación está envuelta con BrowserRouter, el menú de navegación se muestra en todas las rutas y cada página se renderiza según la URL actual.

Si estás preparando tu entorno de desarrollo y quieres trabajar de forma más cómoda desde la terminal, también puede ayudarte este artículo sobre atajos y trucos para usar Visual Studio Code desde la terminal en Mac.

Cómo crear secciones con id en React

Para que un enlace ancla funcione, necesitamos que el destino exista en el DOM. Es decir, si el enlace apunta a #servicios, debe existir un elemento con id="servicios".

Por ejemplo:

function Home() {
  return (
    <main>
      <section id="inicio">
        <h1>Desarrollo frontend y diseño web</h1>
      </section>

      <section id="servicios">
        <h2>Servicios</h2>
      </section>

      <section id="proyectos">
        <h2>Proyectos</h2>
      </section>

      <section id="contacto">
        <h2>Contacto</h2>
      </section>
    </main>
  );
}

export default Home;

Cada sección tiene un identificador único. Este punto es importante: no deberías repetir el mismo id en varias partes de la página.

Los identificadores deben ser claros, breves y descriptivos. Algunos buenos ejemplos serían:

inicio
servicios
proyectos
contacto
preguntas-frecuentes
sobre-mi

En cambio, conviene evitar nombres poco expresivos como:

section1
bloque-final
caja2
x123

Un buen id no solo ayuda a que el enlace funcione correctamente. También mejora la legibilidad del código y facilita el mantenimiento del proyecto.

Una vez instalada la librería, podemos importar HashLink desde react-router-hash-link y utilizarlo dentro de nuestro componente de navegación.

import { HashLink } from "react-router-hash-link";

function Navbar() {
  return (
    <nav>
      <HashLink to="/#inicio">Inicio</HashLink>
      <HashLink to="/#servicios">Servicios</HashLink>
      <HashLink to="/#proyectos">Proyectos</HashLink>
      <HashLink to="/#contacto">Contacto</HashLink>
    </nav>
  );
}

export default Navbar;

Cada enlace apunta a una sección concreta de la página principal.

Por ejemplo:

<HashLink to="/#contacto">Contacto</HashLink>

Este enlace indica dos cosas:

  1. Que debe navegar a la ruta /.
  2. Que debe desplazarse hasta el elemento con id="contacto".

Esta combinación es lo que hace tan útil a React Router Hash Link en aplicaciones con rutas internas.

Cómo añadir smooth scroll

Una de las ventajas más interesantes de React Router Hash Link es que permite añadir desplazamiento suave o smooth scroll de forma muy sencilla.

Solo tenemos que añadir la propiedad smooth:

<HashLink smooth to="/#servicios">
  Servicios
</HashLink>

Con esto, el desplazamiento no se produce de forma brusca, sino con una transición más fluida.

Este detalle mejora mucho la experiencia del usuario, porque le ayuda a entender que se está desplazando a otra parte de la misma página. No hay un salto repentino ni una sensación extraña de cambio de contenido.

El smooth scroll funciona especialmente bien en:

  • Menús de navegación de una landing.
  • Botones de llamada a la acción.
  • Índices de contenido.
  • Páginas de servicios.
  • Portfolios.
  • Secciones de preguntas frecuentes.
  • Formularios de contacto al final de la página.

Aun así, conviene usarlo con criterio. Una animación demasiado lenta o innecesaria puede resultar molesta. El objetivo no es decorar la interfaz, sino ayudar a que la navegación sea más comprensible.

Veamos un ejemplo más completo de un menú de navegación con HashLink y smooth scroll.

import { HashLink } from "react-router-hash-link";

function Navbar() {
  return (
    <header className="site-header">
      <nav className="site-nav">
        <HashLink smooth to="/#inicio">
          Inicio
        </HashLink>

        <HashLink smooth to="/#servicios">
          Servicios
        </HashLink>

        <HashLink smooth to="/#proyectos">
          Proyectos
        </HashLink>

        <HashLink smooth to="/#contacto">
          Contacto
        </HashLink>
      </nav>
    </header>
  );
}

export default Navbar;

Y la página principal podría tener esta estructura:

function Home() {
  return (
    <main>
      <section id="inicio" className="section">
        <h1>Desarrollo frontend y diseño web</h1>
        <p>
          Creo interfaces claras, accesibles y orientadas a la experiencia de usuario.
        </p>
      </section>

      <section id="servicios" className="section">
        <h2>Servicios</h2>
        <p>
          Desarrollo web, optimización frontend y diseño de interfaces.
        </p>
      </section>

      <section id="proyectos" className="section">
        <h2>Proyectos</h2>
        <p>
          Una selección de trabajos realizados con React, WordPress y Astro.
        </p>
      </section>

      <section id="contacto" className="section">
        <h2>Contacto</h2>
        <p>
          ¿Tienes un proyecto en mente? Escríbeme y lo hablamos.
        </p>
      </section>
    </main>
  );
}

export default Home;

Con este patrón ya tenemos una navegación interna funcional, clara y fácil de mantener.

Cómo evitar que el header tape la sección

Un problema muy común al usar enlaces ancla aparece cuando tenemos una cabecera fija o sticky. El enlace funciona, la página se desplaza, pero el título de la sección queda oculto detrás del menú superior.

Para evitarlo, podemos usar la propiedad CSS scroll-margin-top:

.section {
  scroll-margin-top: 90px;
}

También podemos aplicarla a cualquier elemento que tenga un id:

[id] {
  scroll-margin-top: 90px;
}

De esta forma, cuando el navegador haga scroll hasta una sección, dejará un margen superior y el contenido no quedará tapado por la cabecera.

Este tipo de detalle es pequeño, pero marca una gran diferencia en la experiencia de usuario. La navegación no solo debe funcionar: también debe sentirse cómoda y predecible.

Enlaces ancla entre diferentes rutas

React Router Hash Link no solo sirve para moverse dentro de una misma página. También permite enlazar desde una ruta hacia una sección concreta de otra ruta.

Por ejemplo, desde una página /sobre-mi podríamos enviar al usuario directamente al bloque de contacto de la home:

<HashLink smooth to="/#contacto">
  Ir a contacto
</HashLink>

También podríamos apuntar a una sección concreta dentro de otra página:

<HashLink smooth to="/servicios#consultoria">
  Ver consultoría frontend
</HashLink>

Y en la página de servicios tendríamos:

<section id="consultoria">
  <h2>Consultoría frontend</h2>
</section>

Este patrón es muy útil cuando queremos conectar distintas partes de la aplicación sin obligar al usuario a buscar manualmente la sección que le interesa.

Por ejemplo, en una landing podríamos tener un botón como este:

<HashLink smooth className="button" to="/#contacto">
  Solicitar presupuesto
</HashLink>

Este botón funcionaría como una llamada a la acción directa hacia el formulario de contacto.

Es importante no usar HashLink para todo. Cada componente tiene su función.

Link se utiliza para navegar entre rutas:

<Link to="/blog">Blog</Link>

NavLink también navega entre rutas, pero permite aplicar estilos cuando el enlace está activo:

<NavLink to="/blog">Blog</NavLink>

HashLink, en cambio, se utiliza cuando queremos navegar hacia una sección concreta de una página:

<HashLink smooth to="/#proyectos">
  Proyectos
</HashLink>

La clave está en elegir el componente adecuado según la intención del enlace.

Si solo quieres cambiar de página, usa Link o NavLink. Si quieres ir a una sección concreta marcada con un id, usa HashLink.

Buenas prácticas al usar enlaces ancla en React

Para que la implementación sea sólida, conviene seguir algunas buenas prácticas.

Usa textos de enlace descriptivos

El texto del enlace debe explicar claramente hacia dónde lleva.

Mejor esto:

<HashLink smooth to="/#proyectos">
  Ver proyectos destacados
</HashLink>

Que esto:

<HashLink smooth to="/#proyectos">
  Haz clic aquí
</HashLink>

Un texto descriptivo mejora la accesibilidad, ayuda al usuario a entender la acción y hace que la navegación sea más clara.

Mantén una estructura semántica

Los enlaces ancla funcionan mejor cuando la página está bien organizada. Usa encabezados jerárquicos, secciones claras y contenido agrupado de forma lógica.

Por ejemplo:

<section id="servicios">
  <h2>Servicios</h2>
  <p>Texto introductorio de la sección.</p>
</section>

Esta estructura es más clara que una acumulación de div sin significado.

Si trabajas con datos que deben conservarse entre sesiones, puedes complementar esta parte con el artículo sobre cómo usar localStorage y sessionStorage en proyectos JavaScript, ya que también forma parte de la experiencia global de una aplicación frontend.

No abuses de las anclas

Los enlaces ancla son útiles, pero no deberían compensar una mala arquitectura de información.

Si una página necesita demasiados enlaces internos para entenderse, quizá conviene revisar la estructura general del contenido. En desarrollo frontend, la solución técnica debe acompañar siempre a una buena decisión de diseño.

Revisa el comportamiento en móvil

En móvil, los menús suelen ocupar más espacio y las secciones pueden quedar más juntas. Por eso es importante probar que el scroll funciona correctamente en distintos tamaños de pantalla.

También conviene comprobar que el menú no tapa la sección de destino y que los botones tienen un tamaño cómodo para pulsar.

Accesibilidad en enlaces ancla

Cuando trabajamos con navegación interna, no debemos pensar solo en el desplazamiento visual. También es importante tener en cuenta la accesibilidad.

Los enlaces deben ser comprensibles, navegables con teclado y coherentes con la estructura del documento. Además, las secciones de destino deberían tener encabezados claros para que la persona entienda dónde ha llegado.

En algunos proyectos, especialmente si la interfaz es compleja, puede ser necesario gestionar el foco manualmente después del desplazamiento. Esto puede ayudar a personas que navegan con teclado o lector de pantalla.

En proyectos sencillos, una estructura HTML semántica, encabezados claros y enlaces descriptivos ya aportan una base mucho más sólida.

Aunque React Router Hash Link es sencillo de usar, hay algunos errores frecuentes que pueden hacer que los enlaces no funcionen como esperamos.

El id no coincide con el hash

Este es el error más habitual.

Si el enlace apunta a:

<HashLink to="/#contacto">Contacto</HashLink>

Debe existir una sección como esta:

<section id="contacto">
  <h2>Contacto</h2>
</section>

No funcionará si el id se llama de otra manera, por ejemplo:

<section id="contact">
  <h2>Contacto</h2>
</section>

El valor después de # y el valor del id deben coincidir exactamente.

El contenido todavía no se ha renderizado

En React, puede ocurrir que el enlace intente hacer scroll antes de que la sección exista en el DOM. Esto puede pasar si el contenido depende de una petición a una API, una carga condicional o un estado que todavía no se ha actualizado.

En esos casos, conviene revisar cuándo se renderiza la sección y asegurarse de que el elemento de destino existe en el momento adecuado.

No todos los enlaces necesitan ser HashLink.

Si solo quieres navegar a otra ruta, un Link normal es suficiente:

<Link to="/blog">Blog</Link>

Reserva HashLink para los casos en los que quieras apuntar a una sección concreta.

Aunque ambos conceptos utilizan el símbolo #, no son lo mismo.

HashRouter es una forma de gestionar rutas usando el hash de la URL:

/#/servicios

HashLink, en cambio, sirve para navegar hacia una sección concreta dentro de una página:

/#contacto

La diferencia puede parecer sutil, pero es importante. Uno gestiona rutas; el otro gestiona navegación hacia fragmentos internos.

Desde el punto de vista SEO, los enlaces ancla pueden ayudar a organizar mejor el contenido, sobre todo en artículos largos, landings y páginas de documentación.

Un índice interno con enlaces hacia secciones concretas facilita la lectura y permite que el usuario encuentre antes lo que necesita. También permite compartir una URL directa hacia un bloque específico de la página.

Por ejemplo:

https://tusitio.com/blog/react-router-hash-link#smooth-scroll

Ahora bien, React Router Hash Link no es una solución SEO por sí sola. Es una herramienta de navegación. Para posicionar un artículo sobre React, React Router, HashLink, enlaces ancla, smooth scroll, JavaScript y desarrollo frontend, también necesitas:

  • Un título claro y orientado a intención de búsqueda.
  • Una estructura de encabezados bien organizada.
  • Código práctico y explicado paso a paso.
  • Contenido original.
  • Buen rendimiento web.
  • Enlaces internos relevantes.
  • Una buena experiencia móvil.
  • Respuestas claras a dudas frecuentes.

Google no posiciona una página solo porque tenga enlaces ancla. Lo importante es que el contenido resuelva bien la intención de búsqueda y que la experiencia de lectura sea cómoda.

Si te interesa seguir mejorando la parte técnica y de posicionamiento de tus proyectos, puedes ampliar con esta guía sobre SEO OnPage para posicionar tu web en Google.

Merece la pena usar React Router Hash Link cuando tu aplicación React necesita combinar rutas con navegación hacia secciones internas.

Es especialmente útil en:

  • Landings desarrolladas con React.
  • Portfolios de desarrollo frontend.
  • Menús superiores con navegación por secciones.
  • Páginas de servicios.
  • Artículos extensos con índice.
  • Documentación técnica.
  • Formularios de contacto al final de una página.
  • Botones de llamada a la acción.

En cambio, si estás trabajando en una página muy sencilla sin React Router, quizá un enlace HTML tradicional sea suficiente.

La clave está en elegir la herramienta adecuada para el contexto. En desarrollo frontend no siempre gana la solución más compleja, sino la que resuelve mejor el problema con menos fricción.

Aunque React Router Hash Link es una solución muy cómoda, no es la única opción.

Usar enlaces HTML tradicionales

Si todo ocurre dentro de la misma página y no necesitas integración con React Router, podrías usar un enlace normal:

<a href="#contacto">Contacto</a>

Esta opción puede funcionar bien en componentes muy sencillos.

Usar scrollIntoView

También puedes controlar el desplazamiento manualmente con JavaScript:

const scrollToContact = () => {
  document.getElementById("contacto")?.scrollIntoView({
    behavior: "smooth",
  });
};

Y después usarlo en un botón:

<button onClick={scrollToContact}>
  Ir a contacto
</button>

Esta alternativa da más control, pero también implica escribir más lógica manual.

Crear una solución personalizada

En proyectos grandes, puede tener sentido crear una solución propia para controlar el scroll, el foco, el estado activo del menú y otros detalles de accesibilidad.

Sin embargo, para muchos proyectos React, React Router Hash Link ofrece un equilibrio muy práctico entre simplicidad, claridad y funcionalidad.

Sí. React Router Hash Link permite añadir desplazamiento suave usando la propiedad smooth en el componente HashLink.

<HashLink smooth to="/#contacto">
  Contacto
</HashLink>

Con esta propiedad, el usuario no salta bruscamente a la sección, sino que la página se desplaza de forma más fluida.

Sí. Puedes usar HashLink para navegar desde una ruta hacia una sección concreta de otra página.

Por ejemplo:

<HashLink smooth to="/servicios#consultoria">
  Ver consultoría
</HashLink>

Solo necesitas asegurarte de que en la página de destino exista un elemento con el id correspondiente:

<section id="consultoria">
  <h2>Consultoría</h2>
</section>

Link se usa para navegar entre rutas dentro de una aplicación React con React Router. HashLink, en cambio, se usa cuando quieres navegar a una ruta y, además, desplazarte hasta una sección concreta marcada con un id.

Usa Link para rutas generales:

<Link to="/blog">Blog</Link>

Y usa HashLink para enlaces ancla:

<HashLink smooth to="/#proyectos">
  Proyectos
</HashLink>

Navegar mejor también es diseñar mejor

React Router Hash Link es una herramienta sencilla, pero muy útil cuando necesitamos crear enlaces ancla en React dentro de una aplicación gestionada con React Router.

A lo largo del artículo hemos visto qué problema resuelve, cómo instalarla, cómo usar HashLink, cómo activar el smooth scroll, cómo evitar errores comunes y qué buenas prácticas conviene aplicar en proyectos reales de desarrollo frontend.

La idea más importante es que un enlace ancla no es solo un detalle técnico. También es una decisión de experiencia de usuario. Cuando llevamos a una persona directamente a la sección que necesita, reducimos fricción, mejoramos la navegación y hacemos que la interfaz resulte más clara.

En frontend, muchas veces la calidad está en estos pequeños gestos: un menú que no estorba, una sección que aparece justo donde debe, un desplazamiento que orienta en lugar de confundir y una navegación que acompaña al usuario sin exigirle esfuerzo extra.

Por eso, si estás creando una landing, un portfolio, una página de servicios o una documentación en React, React Router Hash Link puede ser una solución muy práctica para mejorar la navegación interna y ofrecer una experiencia más cuidada.

Cómo utilizar mixins en Sass: Ventajas y ejemplos útiles

Cuando un proyecto web empieza a crecer, el CSS también crece con él. Lo que al principio parecía una hoja de estilos sencilla puede convertirse, poco a poco, en un conjunto de reglas repetidas, pequeñas variaciones, media queries duplicadas y patrones difíciles de mantener.

En ese punto, Sass sigue siendo una herramienta muy útil para escribir estilos de forma más ordenada, especialmente cuando trabajamos con arquitectura CSS, componentes reutilizables o sistemas de diseño.

Uno de los recursos más prácticos de Sass son los mixins. Entender cómo utilizar mixins en Sass te permite escribir código más limpio, evitar repeticiones innecesarias y crear patrones reutilizables para botones, layouts, breakpoints, estados visuales, sombras, animaciones o cualquier bloque de estilos que aparezca varias veces en un proyecto.

Si ya has trabajado con Sass o estás valorando incorporarlo a tu flujo de trabajo, puede que también te interese leer este artículo sobre 10 razones para utilizar Sass en tu próximo proyecto, donde explico por qué sigue teniendo sentido en muchos proyectos frontend actuales.

En este artículo vamos a ver qué son los mixins, cuáles son sus ventajas, cuándo conviene utilizarlos, cuándo es mejor evitarlos y varios ejemplos útiles de mixins en Sass que puedes adaptar a tus propios proyectos.

Qué son los mixins en Sass

Un mixin en Sass es un bloque reutilizable de código CSS que se define con @mixin y se utiliza con @include.

Dicho de forma sencilla: un mixin funciona como una pequeña plantilla de estilos. Puedes definir un conjunto de propiedades una sola vez y reutilizarlas en distintos selectores sin tener que copiar y pegar el mismo código una y otra vez.

Por ejemplo, imagina que en tu proyecto utilizas muchas veces el mismo patrón para centrar elementos con Flexbox:

.card {
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal {
  display: flex;
  align-items: center;
  justify-content: center;
}

.hero-content {
  display: flex;
  align-items: center;
  justify-content: center;
}

El código funciona, pero es repetitivo. Si más adelante quieres cambiar la forma de centrar los elementos, tendrás que modificarlo en varios lugares.

Con un mixin, puedes centralizar ese patrón:

@mixin flex-center {
  display: flex;
  align-items: center;
  justify-content: center;
}

.card {
  @include flex-center;
}

.modal {
  @include flex-center;
}

.hero-content {
  @include flex-center;
}

El resultado compilado seguirá siendo CSS normal, pero tu código fuente será más claro, más breve y más fácil de mantener.

Sintaxis básica de un mixin

La sintaxis mínima de un mixin en Sass es esta:

@mixin nombre-del-mixin {
  propiedad: valor;
  propiedad: valor;
}

Y para utilizarlo dentro de un selector:

.selector {
  @include nombre-del-mixin;
}

Un ejemplo muy básico podría ser el de una tarjeta reutilizable:

@mixin card-base {
  border-radius: 1rem;
  padding: 1.5rem;
  background-color: #ffffff;
  box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.08);
}

.article-card {
  @include card-base;
}

.project-card {
  @include card-base;
}

Este mixin crea una base visual común para tarjetas. Después, cada componente puede añadir sus propias variaciones:

.project-card {
  @include card-base;
  border: 1px solid #e8e8e8;
}

Así consigues una base consistente sin renunciar a la personalización.

Resultado CSS compilado

Cuando Sass compila el código anterior, el navegador no ve @mixin ni @include. Solo recibe CSS estándar:

.article-card {
  border-radius: 1rem;
  padding: 1.5rem;
  background-color: #ffffff;
  box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.08);
}

.project-card {
  border-radius: 1rem;
  padding: 1.5rem;
  background-color: #ffffff;
  box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.08);
  border: 1px solid #e8e8e8;
}

Esto es importante: Sass no se ejecuta directamente en el navegador. Sass se compila antes y genera CSS final. Por eso, los mixins son una herramienta de organización en tiempo de desarrollo.

Ventajas de utilizar mixins en Sass

Los mixins no sirven únicamente para escribir menos código. Bien utilizados, pueden mejorar la arquitectura de estilos de un proyecto completo.

Reducen la repetición de código

La ventaja más evidente es que ayudan a evitar bloques repetidos. Esto encaja con el principio DRY, es decir, Don’t Repeat Yourself, muy habitual en desarrollo.

Si repites muchas veces el mismo patrón visual, un mixin puede ayudarte a mantenerlo en un único lugar. Por ejemplo:

@mixin transition-base {
  transition: all 0.25s ease;
}

.button {
  @include transition-base;
}

.card {
  @include transition-base;
}

.nav-link {
  @include transition-base;
}

Ahora, si decides ajustar la duración de la transición, solo tienes que cambiar el mixin:

@mixin transition-base {
  transition: all 0.2s ease-in-out;
}

Ese cambio se aplicará a todos los selectores que incluyan el mixin.

Si quieres profundizar más en cómo funcionan las transiciones y cuándo conviene usarlas frente a las animaciones, puedes leer también el artículo sobre la diferencia entre transition y animation en CSS.

Mejoran la consistencia visual

En proyectos con muchas páginas, componentes o personas tocando el mismo código, es fácil que aparezcan pequeñas inconsistencias: botones con radios diferentes, sombras ligeramente distintas, espaciados no alineados o breakpoints duplicados con valores diferentes.

Los mixins ayudan a crear patrones compartidos. Por ejemplo, puedes definir una sombra estándar:

@mixin soft-shadow {
  box-shadow: 0 0.75rem 2rem rgba(0, 0, 0, 0.08);
}

Y aplicarla en todos los componentes que necesiten ese mismo tratamiento visual:

.pricing-card {
  @include soft-shadow;
}

.testimonial {
  @include soft-shadow;
}

Esto no solo mejora el código, también mejora la coherencia de la interfaz.

Permiten crear patrones flexibles con argumentos

Una de las grandes ventajas de los mixins es que pueden recibir argumentos. Esto significa que no tienen por qué generar siempre el mismo CSS exacto.

Puedes pasarles valores para crear variaciones controladas:

@mixin button-variant($bg-color, $text-color) {
  background-color: $bg-color;
  color: $text-color;
  border: none;
  border-radius: 999px;
  padding: 0.75rem 1.25rem;
  font-weight: 600;
  cursor: pointer;
}

.button-primary {
  @include button-variant(#cc2b5e, #ffffff);
}

.button-secondary {
  @include button-variant(#f8e0ea, #753a88);
}

Este mixin permite crear variantes de botón sin repetir toda la estructura.

También puedes usar valores por defecto:

@mixin button-variant($bg-color: #cc2b5e, $text-color: #ffffff) {
  background-color: $bg-color;
  color: $text-color;
  border: none;
  border-radius: 999px;
  padding: 0.75rem 1.25rem;
  font-weight: 600;
}

Así puedes llamar al mixin sin argumentos:

.button-primary {
  @include button-variant;
}

O sobrescribir solo cuando lo necesites:

.button-light {
  @include button-variant(#ffffff, #020101);
}

Facilitan la gestión de media queries

Uno de los usos más habituales de los mixins en Sass es la gestión de breakpoints. En lugar de escribir media queries manualmente en cada componente, puedes centralizarlas.

@mixin respond-to($breakpoint) {
  @if $breakpoint == tablet {
    @media (min-width: 768px) {
      @content;
    }
  }

  @if $breakpoint == desktop {
    @media (min-width: 1024px) {
      @content;
    }
  }

  @if $breakpoint == wide {
    @media (min-width: 1280px) {
      @content;
    }
  }
}

Después puedes usarlo así:

.hero {
  padding: 3rem 1.5rem;

  @include respond-to(tablet) {
    padding: 4rem 2rem;
  }

  @include respond-to(desktop) {
    padding: 6rem 4rem;
  }
}

Aquí aparece @content, una característica muy útil de Sass que permite pasar un bloque de estilos dentro del @include.

Este patrón resulta especialmente interesante cuando trabajas con diseño responsive. En ese contexto, también puedes revisar el artículo sobre cómo utilizar media queries internas en imágenes SVG.

Cómo utilizar mixins en Sass paso a paso

Para sacarles partido, no basta con saber escribir @mixin. También conviene pensar dónde colocarlos, cómo nombrarlos y cómo evitar que se conviertan en una capa de abstracción innecesaria.

Paso 1: detecta patrones repetidos

Antes de crear un mixin, pregúntate si ese bloque de estilos se repite de verdad, si lo vas a necesitar en más de dos o tres sitios y si representa un patrón del proyecto.

Buenos candidatos para convertirse en mixins:

  • Centrado con Flexbox.
  • Media queries.
  • Estilos base de botones.
  • Estados hover y focus.
  • Estilos visuales reutilizables.
  • Helpers de accesibilidad.
  • Patrones de truncado de texto.
  • Animaciones repetidas.
  • Contenedores con ancho máximo.

En cambio, no suele ser buena idea crear un mixin para un estilo que solo se usa una vez o para un bloque demasiado específico de un componente.

Un mixin debe resolver un problema concreto. Si el nombre del mixin tiene que explicar demasiadas cosas, probablemente está haciendo demasiado.

Paso 2: usa nombres claros

Los nombres importan. Un buen nombre permite entender qué hace el mixin sin tener que abrir su definición.

Mejor esto:

@mixin visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

Que esto:

@mixin hidden-thing {
  position: absolute;
  width: 1px;
  height: 1px;
}

El primer nombre comunica intención. El segundo no.

También conviene evitar nombres demasiado genéricos como box, style, effect o custom. En un proyecto grande, esos nombres se vuelven difíciles de mantener.

Paso 3: organiza los mixins en archivos separados

En proyectos pequeños puedes escribir los mixins en el mismo archivo, pero en un proyecto real conviene separarlos.

Una estructura sencilla podría ser:

scss/
  abstracts/
    _variables.scss
    _mixins.scss
  base/
    _reset.scss
    _typography.scss
  components/
    _buttons.scss
    _cards.scss
  main.scss

En Sass moderno es recomendable trabajar con @use y @forward en lugar de depender de @import.

Por ejemplo:

// abstracts/_mixins.scss

@mixin flex-center {
  display: flex;
  align-items: center;
  justify-content: center;
}

Luego, en otro archivo:

@use "../abstracts/mixins" as mixins;

.card {
  @include mixins.flex-center;
}

Este enfoque evita contaminar el espacio global y hace que el origen de cada mixin sea más claro.

Ejemplos útiles de mixins en Sass

A continuación tienes varios ejemplos prácticos que puedes adaptar a tus propios proyectos.

Mixin para centrar elementos con Flexbox

@mixin flex-center($direction: row, $gap: 0) {
  display: flex;
  flex-direction: $direction;
  align-items: center;
  justify-content: center;
  gap: $gap;
}

.empty-state {
  @include flex-center(column, 1rem);
  min-height: 20rem;
  text-align: center;
}

Este mixin es útil para componentes como modales, tarjetas vacías, secciones hero o layouts centrados.

Mixin para media queries

@mixin media-up($size) {
  @if $size == sm {
    @media (min-width: 640px) {
      @content;
    }
  }

  @if $size == md {
    @media (min-width: 768px) {
      @content;
    }
  }

  @if $size == lg {
    @media (min-width: 1024px) {
      @content;
    }
  }

  @if $size == xl {
    @media (min-width: 1280px) {
      @content;
    }
  }
}

Uso:

.blog-grid {
  display: grid;
  gap: 1.5rem;

  @include media-up(md) {
    grid-template-columns: repeat(2, 1fr);
  }

  @include media-up(lg) {
    grid-template-columns: repeat(3, 1fr);
  }
}

Este patrón ayuda a mantener las media queries consistentes y evita escribir valores sueltos por todo el proyecto.

Mixin para botones reutilizables

@mixin button-base {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  border: 0;
  border-radius: 999px;
  padding: 0.85rem 1.4rem;
  font: inherit;
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  transition:
    transform 0.2s ease,
    background-color 0.2s ease,
    color 0.2s ease;
}

@mixin button-theme($bg, $color, $hover-bg) {
  background-color: $bg;
  color: $color;

  &:hover {
    background-color: $hover-bg;
    transform: translateY(-2px);
  }

  &:focus-visible {
    outline: 3px solid rgba($bg, 0.35);
    outline-offset: 3px;
  }
}

.button-primary {
  @include button-base;
  @include button-theme(#cc2b5e, #ffffff, #753a88);
}

.button-soft {
  @include button-base;
  @include button-theme(#f8e0ea, #753a88, #f1c4d7);
}

Aquí separamos la estructura del botón de su tema visual. Esto hace que el código sea más fácil de escalar.

Mixin para texto oculto visualmente

Este tipo de mixin es útil cuando queremos ocultar texto de forma visual pero mantenerlo disponible para tecnologías de asistencia.

@mixin visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.icon-button span {
  @include visually-hidden;
}

Este patrón puede ser útil en botones que solo muestran un icono, pero que necesitan conservar un nombre accesible para lectores de pantalla.

Mixin para truncar texto

@mixin truncate($lines: 1) {
  overflow: hidden;

  @if $lines == 1 {
    white-space: nowrap;
    text-overflow: ellipsis;
  } @else {
    display: -webkit-box;
    -webkit-line-clamp: $lines;
    -webkit-box-orient: vertical;
  }
}

.card-title {
  @include truncate(2);
}

Este mixin permite reutilizar un patrón muy habitual en tarjetas de blog, listados de productos o interfaces con contenido dinámico.

Mixin para mantener proporciones de imagen

@mixin aspect-ratio($width, $height) {
  aspect-ratio: #{$width} / #{$height};
  overflow: hidden;

  > img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
}

.post-card__media {
  @include aspect-ratio(3, 2);
  border-radius: 1rem;
}

Este mixin es práctico cuando quieres mantener una línea visual consistente en imágenes destacadas, galerías o tarjetas.

Mixins en Sass vs variables CSS: cuándo usar cada uno

Una duda habitual es si tiene sentido seguir usando Sass cuando CSS moderno ya incluye custom properties, también conocidas como variables CSS.

La respuesta corta es: sí, pero no para lo mismo.

Las variables CSS se declaran con la sintaxis --nombre-variable y se consumen mediante var(). Además, participan en la cascada y pueden cambiar según el contexto del elemento. Esto las hace muy útiles para temas, modos claro/oscuro o valores dinámicos.

Por ejemplo:

:root {
  --color-primary: #cc2b5e;
}

.button {
  background-color: var(--color-primary);
}

Un mixin, en cambio, no existe en tiempo de ejecución. Se compila antes de llegar al navegador.

Por eso, un mixin es ideal para generar bloques completos de CSS, mientras que una variable CSS es ideal para valores que pueden cambiar según el contexto.

Usa mixins cuando necesites generar patrones de CSS

Por ejemplo:

@mixin focus-ring($color) {
  &:focus-visible {
    outline: 3px solid $color;
    outline-offset: 4px;
  }
}

.link {
  @include focus-ring(#cc2b5e);
}

Usa variables CSS cuando necesites valores dinámicos

:root {
  --focus-color: #cc2b5e;
}

[data-theme="dark"] {
  --focus-color: #f8e0ea;
}

.link:focus-visible {
  outline: 3px solid var(--focus-color);
}

En muchos proyectos, la mejor solución es combinar ambas herramientas: Sass para organizar y generar CSS, y variables CSS para gestionar valores que deben adaptarse al contexto.

Errores comunes al utilizar mixins en Sass

Los mixins son útiles, pero también pueden utilizarse mal. Estos son algunos errores frecuentes que conviene evitar.

Crear mixins para todo

No todo necesita ser un mixin. Si un bloque de estilos solo se utiliza una vez, probablemente no merece convertirse en una abstracción.

Un exceso de mixins puede hacer que el CSS sea más difícil de leer, porque obliga a saltar constantemente entre archivos para entender qué estilos se están aplicando.

Crear mixins demasiado grandes

Un mixin debería tener una responsabilidad clara. Este ejemplo es problemático:

@mixin complete-card-system {
  display: grid;
  padding: 2rem;
  border-radius: 1rem;
  background: white;
  color: black;
  box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.12);

  h2 {
    font-size: 2rem;
  }

  p {
    color: gray;
  }

  a {
    color: red;
  }
}

Este mixin mezcla layout, estilos visuales, tipografía y estilos de elementos internos. Puede parecer cómodo al principio, pero a la larga será difícil de mantener.

Es mejor dividirlo en piezas pequeñas:

@mixin card-surface {
  border-radius: 1rem;
  background: white;
  box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.12);
}

@mixin content-flow($gap: 1rem) {
  display: grid;
  gap: $gap;
}

Así puedes combinar solo lo que necesites.

Usar mixins para valores simples

Si solo quieres reutilizar un color, un tamaño o un espaciado, probablemente sea mejor usar una variable Sass o una variable CSS.

No tiene mucho sentido hacer esto:

@mixin primary-color {
  color: #cc2b5e;
}

En este caso, sería más claro usar una variable:

$color-primary: #cc2b5e;

.title {
  color: $color-primary;
}

O una custom property si quieres que el valor sea dinámico:

.title {
  color: var(--color-primary);
}

Buenas prácticas para escribir mixins mantenibles

Para que los mixins sigan siendo útiles con el paso del tiempo, conviene aplicar algunas buenas prácticas.

Mantén una responsabilidad por mixin

Un mixin debería resolver una cosa concreta: centrar elementos, aplicar una media query, generar una variante de botón, crear un estado de foco o definir una superficie visual.

Si un mixin empieza a crecer demasiado, divídelo.

Usa argumentos con nombres claros

Los argumentos deben ser fáciles de entender:

@mixin container($max-width: 72rem, $padding-inline: 1.5rem) {
  width: min(100% - (#{$padding-inline} * 2), #{$max-width});
  margin-inline: auto;
}

Uso:

.page-wrapper {
  @include container(80rem, 2rem);
}

También puedes usar argumentos nombrados para mejorar la legibilidad:

.page-wrapper {
  @include container($max-width: 80rem, $padding-inline: 2rem);
}

Documenta los mixins importantes

No hace falta comentar todo, pero sí conviene documentar los mixins que forman parte de la arquitectura del proyecto.

/// Crea un contenedor centrado con ancho máximo y padding lateral.
/// @param {Length} $max-width - Ancho máximo del contenedor.
/// @param {Length} $padding-inline - Espaciado lateral mínimo.
@mixin container($max-width: 72rem, $padding-inline: 1.5rem) {
  width: min(100% - (#{$padding-inline} * 2), #{$max-width});
  margin-inline: auto;
}

Esta pequeña documentación puede ahorrar mucho tiempo cuando el proyecto crece o cuando otra persona se incorpora al código.

Evita esconder demasiada lógica

Los mixins deben ayudarte, no convertirse en una caja negra. Si un @include genera demasiadas reglas inesperadas, puede dificultar la depuración en el navegador.

Un buen mixin debe ser predecible.

Cuándo conviene utilizar mixins en Sass

Los mixins son especialmente útiles cuando existe un patrón repetible con cierta lógica.

Por ejemplo:

@mixin hover-lift($distance: -3px) {
  transition:
    transform 0.2s ease,
    box-shadow 0.2s ease;

  &:hover {
    transform: translateY($distance);
    box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.12);
  }
}

Uso:

.article-card {
  @include hover-lift;
}

.project-card {
  @include hover-lift(-5px);
}

También son muy útiles cuando quieres crear una API interna para tus estilos. Por ejemplo, un equipo puede acordar que todos los componentes usen el mismo mixin para los estados de foco:

@mixin accessible-focus($color: #cc2b5e) {
  &:focus-visible {
    outline: 3px solid $color;
    outline-offset: 4px;
  }
}

De esta manera, la accesibilidad visual se vuelve más consistente en todo el proyecto.

Y si estás trabajando con movimiento en interfaces, conviene recordar que no todo tiene que resolverse con CSS puro. Para ciertos casos más avanzados, puedes combinar Sass con librerías específicas. En ese contexto, puede interesarte este artículo sobre cómo crear animaciones para la web con la librería GSAP.

Preguntas frecuentes sobre mixins en Sass

¿Cuál es la diferencia entre un mixin y una función en Sass?

Una función en Sass devuelve un valor, mientras que un mixin genera un bloque de declaraciones CSS.

Por ejemplo, una función puede calcular un tamaño o devolver un color transformado. Un mixin, en cambio, puede generar varias propiedades como display, align-items, justify-content, padding, border-radius o incluso media queries completas.

En resumen: usa funciones para valores y mixins para bloques de estilos reutilizables.

¿Es buena idea utilizar mixins para responsive design?

Sí, siempre que se usen con criterio. Los mixins para media queries ayudan a centralizar los breakpoints y evitar inconsistencias.

En lugar de escribir @media (min-width: 768px) en veinte archivos diferentes, puedes crear un mixin como media-up(md) y usarlo en todos los componentes.

Esto mejora la mantenibilidad y hace que el sistema responsive del proyecto sea más fácil de modificar.

¿Los mixins aumentan el tamaño del CSS final?

Pueden hacerlo si se abusa de ellos. Cada vez que incluyes un mixin, Sass copia su contenido en el selector correspondiente.

Si un mixin genera muchas propiedades y lo usas en demasiados lugares, el CSS compilado puede crecer.

Por eso es importante utilizar mixins para patrones realmente reutilizables, no como sustituto automático de cualquier declaración CSS.

Escribir menos no siempre es escribir mejor

Los mixins en Sass son una herramienta muy poderosa para escribir CSS más organizado, reutilizable y coherente. Permiten reducir repetición, centralizar patrones, crear variantes mediante argumentos y trabajar mejor con media queries, estados visuales o estructuras comunes de componentes.

Sin embargo, como ocurre con cualquier abstracción, su valor depende de cómo se utilicen. Un buen mixin hace que el código sea más claro. Un mal mixin puede convertir una hoja de estilos en un sistema difícil de seguir.

La clave está en usarlos con intención. Antes de crear un mixin, pregúntate si realmente estás resolviendo un patrón repetido, si el nombre comunica bien su propósito y si el resultado será más fácil de mantener dentro de unos meses.

Sass sigue teniendo sentido en muchos flujos de trabajo modernos, especialmente cuando se combina con CSS actual, variables personalizadas, arquitectura modular y una buena organización de componentes.

En definitiva, aprender cómo utilizar mixins en Sass no consiste solo en memorizar @mixin y @include. Consiste en desarrollar criterio para detectar patrones, reducir ruido y construir una base de estilos más sólida para tus proyectos frontend.