Estilo global versus local en Next.js

 

 

 

  • Creación y mantenimiento de sistemas de diseño exitosos, con Brad Fost
  • Patrones de diseño de interfaces inteligentes, vídeo de 10h + formación UX

  • Índice
    1. Escribir CSS "anticuado"
    2. Empezando
    3. Fichas de diseño
    4. Estilos globales
    5. Clases de utilidad
    6. Estilos de componentes
      1. Colocación de estilos con componentes a través de módulos CSS
      2. Combinando estilo global y local
    7. Un acto de equilibrio

    Next.js tiene opiniones firmes sobre cómo organizar JavaScript pero no CSS. ¿Cómo podemos desarrollar patrones que fomenten las mejores prácticas de CSS y al mismo tiempo sigan la lógica del marco? La respuesta es sorprendentemente simple: escribir CSS bien estructurado que equilibre las preocupaciones de estilo locales y globales.

     

    He tenido una gran experiencia usando Next.js para gestionar proyectos front-end complejos. Next.js tiene opiniones sobre cómo organizar el código JavaScript, pero no tiene opiniones integradas sobre cómo organizar CSS.

    Después de trabajar dentro del marco, encontré una serie de patrones organizativos que creo que se ajustan a las filosofías rectoras de Next.js y ejercen las mejores prácticas de CSS. En este artículo, crearemos juntos un sitio web (¡una tienda de té!) para demostrar estos patrones.

    Nota : Probablemente no necesites experiencia previa en Next.js, aunque sería bueno tener un conocimiento básico de React y estar abierto a aprender algunas técnicas nuevas de CSS.

    Escribir CSS "anticuado"

    Cuando analizamos Next.js por primera vez, podemos sentir la tentación de considerar el uso de algún tipo de biblioteca CSS-in-JS. Aunque puede haber beneficios según el proyecto, CSS-in-JS introduce muchas consideraciones técnicas. Requiere el uso de una nueva biblioteca externa, lo que aumenta el tamaño del paquete. CSS-in-JS también puede tener un impacto en el rendimiento al provocar representaciones y dependencias adicionales en el estado global.

    Lectura recomendada : " Los costos de rendimiento invisibles de las bibliotecas CSS-in-JS modernas en aplicaciones React )" por Aggelos Arvanitakis

    Además, el objetivo de utilizar una biblioteca como Next.js es representar recursos estáticamente siempre que sea posible, por lo que no tiene mucho sentido escribir JS que deba ejecutarse en el navegador para generar CSS.

     

    Hay un par de preguntas que debemos considerar al organizar el estilo en Next.js:

    ¿Cómo podemos encajar dentro de las convenciones/mejores prácticas del marco?

    ¿Cómo podemos equilibrar las preocupaciones de estilo “globales” (fuentes, colores, diseños principales, etc.) con las “locales” (estilos relacionados con componentes individuales)?

    La respuesta que se me ocurrió para la primera pregunta es simplemente escribir CSS a la antigua usanza . Next.js no solo admite hacerlo sin configuración adicional; también produce resultados que son eficientes y estáticos.

    Para resolver el segundo problema, adopto un enfoque que se puede resumir en cuatro partes:

    1. Fichas de diseño
    2. Estilos globales
    3. Clases de utilidad
    4. Estilos de componentes

    Estoy en deuda con la idea de Andy Bell de CUBE CSS ("Composición, Utilidad, Bloque, Excepción") aquí. Si no ha oído hablar de este principio organizativo antes, le recomendé que consulte su sitio oficial o su función en Smashing Podcast . Uno de los principios que tomaremos de CUBE CSS es la idea de que debemos abrazar , en lugar de temer, la cascada de CSS. Aprendamos estas técnicas aplicándolas a un proyecto de sitio web.

    Empezando

    Construiremos una tienda de té porque, bueno, el té es delicioso. Comenzaremos ejecutando yarn create next-apppara crear un nuevo proyecto Next.js. Luego, eliminaremos todo lo que hay en styles/ directory(todo es código de muestra).

    Nota : Si desea seguir el proyecto terminado, puede consultarlo aquí .

    Fichas de diseño

    En prácticamente cualquier configuración de CSS, existe un claro beneficio al almacenar todos los valores compartidos globalmente en variables . Si un cliente solicita cambiar un color, implementar el cambio es una simple línea en lugar de un lío masivo de buscar y reemplazar. En consecuencia, una parte clave de nuestra configuración CSS de Next.js será almacenar todos los valores de todo el sitio como tokens de diseño .

    Usaremos propiedades personalizadas de CSS incorporadas para almacenar estos tokens. (Si no está familiarizado con esta sintaxis, puede consultar “ Una guía estratégica para las propiedades personalizadas de CSS ”.) Debo mencionar que (en algunos proyectos) he optado por usar variables SASS/SCSS para este propósito. No he encontrado ninguna ventaja real, por lo que generalmente solo incluyo SASS en un proyecto si encuentro que necesito otras funciones de SASS (mezclas, iteración, importación de archivos, etc.). Las propiedades personalizadas de CSS, por el contrario, también funcionan con la cascada y se pueden cambiar con el tiempo en lugar de compilarlas estáticamente. Entonces, por hoy, sigamos con CSS simple .

    En nuestro styles/directorio, creemos un nuevo archivo design_tokens.css :

    :root { --green: #3FE79E; --dark: #0F0235; --off-white: #F5F5F3; --space-sm: 0.5rem; --space-md: 1rem; --space-lg: 1.5rem; --font-size-sm: 0.5rem; --font-size-md: 1rem; --font-size-lg: 2rem;}

    Por supuesto, esta lista puede crecer y crecerá con el tiempo. Una vez que agreguemos este archivo, debemos saltar a nuestro archivo páginas/_app.jsx , que es el diseño principal de todas nuestras páginas, y agregar:

     

    import '../styles/design_tokens.css'

    Me gusta pensar en los tokens de diseño como el pegamento que mantiene la coherencia en todo el proyecto. Haremos referencia a estas variables a escala global, así como dentro de componentes individuales, asegurando un lenguaje de diseño unificado.

    Estilos globales

    A continuación, ¡agreguemos una página a nuestro sitio web! Vayamos al archivo páginas/index.jsx (esta es nuestra página de inicio). Eliminaremos todo el texto estándar y agregaremos algo como:

    export default function Home() { return main h1Soothing Teas/h1 pWelcome to our wonderful tea shop./p pWe have been open since 1987 and serve customers with hand-picked oolong teas./p /main}

    Desafortunadamente, se verá bastante sencillo, así que establezcamos algunos estilos globales para elementos básicos , por ejemplo, h1etiquetas. (Me gusta pensar en estos estilos como “valores predeterminados globales razonables”.) Podemos anularlos en casos específicos, pero son una buena suposición de lo que querremos si no lo hacemos.

    Pondré esto en el archivo estilos/globals.css (que viene de forma predeterminada desde Next.js):

    *,*::before,*::after { box-sizing: border-box;}body { color: var(--off-white); background-color: var(--dark);}h1 { color: var(--green); font-size: var(--font-size-lg);}p { font-size: var(--font-size-md);}p, article, section { line-height: 1.5;}:focus { outline: 0.15rem dashed var(--off-white); outline-offset: 0.25rem;}main:focus { outline: none;}img { max-width: 100%;}

    Por supuesto, esta versión es bastante básica, pero mi archivo globals.css generalmente no necesita crecer demasiado. Aquí, diseño elementos HTML básicos (títulos, cuerpo, enlaces, etc.). No es necesario incluir estos elementos en componentes de React ni agregar clases constantemente solo para proporcionar un estilo básico.

    También incluyo cualquier restablecimiento de los estilos predeterminados del navegador . De vez en cuando, tendré algún estilo de diseño para todo el sitio para proporcionar un "pie de página fijo", por ejemplo, pero solo pertenecen aquí si todas las páginas comparten el mismo diseño. De lo contrario, será necesario abarcarlo dentro de componentes individuales.

    Siempre incluyo algún tipo de :focusestilo para indicar claramente los elementos interactivos para los usuarios del teclado cuando están enfocados. ¡Es mejor convertirlo en una parte integral del ADN del diseño del sitio!

    Ahora, nuestro sitio web está empezando a tomar forma:

     

    Imagen del sitio web del trabajo en progreso. El fondo de la página ahora es de color azul oscuro y el título "Tés calmantes" es verde. El sitio web no tiene diseño/espaciado y, por lo tanto, se extiende completamente a lo ancho de la ventana del navegador. ( Vista previa grande )

    Clases de utilidad

    Un área donde nuestra página de inicio ciertamente podría mejorar es que actualmente el texto siempre se extiende a los lados de la pantalla, así que limitemos su ancho. Necesitamos este diseño en esta página, pero imagino que es posible que también lo necesitemos en otras páginas. ¡Este es un gran caso de uso para una clase de servicios públicos!

    Intento usar clases de utilidad con moderación en lugar de reemplazar simplemente escribir CSS. Mis criterios personales sobre cuándo tiene sentido agregar uno a un proyecto son:

    1. Lo necesito repetidamente;
    2. Hace una cosa bien;
    3. Se aplica a una variedad de componentes o páginas diferentes.

    Creo que este caso cumple con los tres criterios, así que creemos un nuevo archivo CSS estilos/utilidades.css y agreguemos:

    .lockup { max-width: 90ch; margin: 0 auto;}

    Luego agreguemos importación '../styles/utilities.css'a nuestras páginas/_app.jsx . Finalmente, cambiemos la mainetiqueta en nuestras páginas/index.jsx a main className="lockup".

    Ahora nuestra página se está uniendo aún más. Debido a que utilizamos la max-widthpropiedad, no necesitamos ninguna consulta de medios para que nuestro diseño responda a dispositivos móviles. Y, debido a que utilizamos la chunidad de medida, que equivale aproximadamente al ancho de un carácter, nuestro tamaño es dinámico según el tamaño de fuente del navegador del usuario.

    El mismo sitio web que antes, pero ahora el texto se fija en el medio y no se ensancha demasiado. ( Vista previa grande )

    A medida que nuestro sitio web crezca, podremos seguir agregando más clases de servicios públicos. Adopto un enfoque bastante utilitario aquí: si estoy trabajando y encuentro que necesito otra clase para un color o algo así, la agrego. No agrego todas las clases posibles bajo el sol; aumentaría el tamaño del archivo CSS y haría que mi código fuera confuso. A veces, en proyectos más grandes, me gusta dividir las cosas en un styles/utilities/directorio con algunos archivos diferentes; Depende de las necesidades del proyecto.

    Podemos pensar en las clases de utilidad como nuestro conjunto de herramientas de comandos de estilo comunes y repetidos que se comparten globalmente. Nos ayudan a evitar que reescribamos constantemente el mismo CSS entre diferentes componentes.

    Estilos de componentes

    Hemos terminado nuestra página de inicio por el momento, pero aún nos falta construir una parte de nuestro sitio web: la tienda en línea. Nuestro objetivo aquí será mostrar una cuadrícula de tarjetas de todos los tés que queremos vender , por lo que necesitaremos agregar algunos componentes a nuestro sitio.

    Comencemos agregando una nueva página en páginas/shop.jsx :

    export default function Shop() { return main div className="lockup" h1Shop Our Teas/h1 /div /main}

    Luego, necesitaremos algunos tés para exhibir. Incluiremos un nombre, descripción e imagen (en el directorio público/) para cada té: calculadora de dias fertiles

     

    const teas = [ { name: "Oolong", description: "A partially fermented tea.", image: "/oolong.jpg" }, // ...]

    Nota : Este no es un artículo sobre la obtención de datos , por lo que tomamos el camino fácil y definimos una matriz al principio del archivo.

    A continuación, necesitaremos definir un componente para mostrar nuestros tés. Comencemos creando un components/directorio (Next.js no lo crea de forma predeterminada). Luego, agreguemos un components/TeaListdirectorio. Para cualquier componente que termine necesitando más de un archivo, normalmente coloco todos los archivos relacionados dentro de una carpeta. Hacerlo evita que nuestra components/carpeta se vuelva innavegable.

    Ahora, agreguemos nuestro archivo componentes/TeaList/TeaList.jsx :

    import TeaListItem from './TeaListItem'const TeaList = (props) = { const { teas } = props return ul role="list" {teas.map(tea = TeaListItem tea={tea} key={tea.name} /)} /ul}export default TeaList

    El propósito de este componente es iterar sobre nuestros tés y mostrar un elemento de lista para cada uno, así que ahora definamos nuestro componente componentes/TeaList/TeaListItem.jsx :

    import Image from 'next/image'const TeaListItem = (props) = { const { tea } = props return li div Image src={tea.image} objectFit="cover" objectPosition="center" layout="fill" / /div div h2{tea.name}/h2 p{tea.description}/p /div /li}export default TeaListItem

    Tenga en cuenta que estamos utilizando el componente de imagen integrado de Next.js. Establecí el altatributo en una cadena vacía porque las imágenes son puramente decorativas en este caso; Queremos evitar atascar a los usuarios de lectores de pantalla con largas descripciones de imágenes aquí.

    Finalmente, creemos un archivo componentes/TeaList/index.js , para que nuestros componentes sean fáciles de importar externamente:

    import TeaList from './TeaList'import TeaListItem from './TeaListItem'export { TeaListItem }export default TeaList

    Y luego, conectemos todo agregando import TeaList from ../components/TeaListy un TeaList teas={teas} /elemento a nuestra página de Tienda. Ahora, nuestros tés aparecerán en una lista, pero no será tan bonito.

    Colocación de estilos con componentes a través de módulos CSS

    Comencemos diseñando nuestras tarjetas (el TeaListLitemcomponente). Ahora, por primera vez en nuestro proyecto, vamos a querer agregar un estilo que sea específico de un solo componente. Creemos un nuevo archivo componentes/TeaList/TeaListItem.module.css .

    Quizás se pregunte acerca del módulo en la extensión del archivo. Este es un módulo CSS . Next.js admite módulos CSS e incluye buena documentación sobre ellos. Cuando escribimos un nombre de clase desde un módulo CSS como .TeaListItem, automáticamente se transformará en algo más parecido . TeaListItem_TeaListItem__TFOk_con un montón de caracteres adicionales añadidos. En consecuencia, podemos usar cualquier nombre de clase que queramos sin preocuparnos de que entre en conflicto con otros nombres de clase en otras partes de nuestro sitio.

     

    Otra ventaja de los módulos CSS es el rendimiento. Next.js incluye una función de importación dinámica . next/dynamic nos permite cargar componentes de forma diferida para que su código solo se cargue cuando sea necesario, en lugar de aumentar el tamaño del paquete completo. Si importamos los estilos locales necesarios en componentes individuales, los usuarios también pueden cargar de forma diferida el CSS para componentes importados dinámicamente . Para proyectos grandes, podemos optar por cargar de forma diferida partes importantes de nuestro código y solo cargar el JS/CSS más necesario por adelantado. Como resultado, normalmente termino creando un nuevo archivo de módulo CSS para cada componente nuevo que necesita un estilo local.

    Comencemos agregando algunos estilos iniciales a nuestro archivo:

    .TeaListItem { display: flex; flex-direction: column; gap: var(--space-sm); background-color: var(--color, var(--off-white)); color: var(--dark); border-radius: 3px; box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);}

    Luego, podemos importar estilo desde ./TeaListItem.module.cssnuestro TeaListitemcomponente. La variable de estilo viene como un objeto JavaScript, por lo que podemos acceder a esta clase.style.TeaListItem.

    Nota : No es necesario que el nombre de nuestra clase esté en mayúscula. Descubrí que una convención de nombres de clases en mayúscula dentro de los módulos (y en minúsculas afuera) diferencia visualmente los nombres de clases locales versus globales.

    Entonces, tomemos nuestra nueva clase local y asignémosla a linuestro TeaListItemcomponente:

    li className={style.TeaListComponent}

    Quizás se pregunte acerca de la línea de color de fondo (es decir var(--color, var(--off-white));). Lo que este fragmento significa es que, de forma predeterminada, el fondo será nuestro --off-whitevalor. Pero, si configuramos una --colorpropiedad personalizada en una tarjeta, se anulará y elegirá ese valor.

    Al principio, queremos que todas nuestras tarjetas sean --off-white, pero es posible que deseemos cambiar el valor de tarjetas individuales más adelante. Esto funciona de manera muy similar a los accesorios en React. Podemos establecer un valor predeterminado pero crear un espacio donde podamos elegir otros valores en circunstancias específicas. Por lo tanto, nos animo a pensar en propiedades personalizadas de CSS como la versión de accesorios de CSS .

    El estilo aún no se verá bien porque queremos asegurarnos de que las imágenes permanezcan dentro de sus contenedores. El componente Imagen de Next.js con el layout="fill"accesorio se obtiene position: absolute;del marco, por lo que podemos limitar el tamaño colocándolo en un contenedor con posición: relativa;.

    Agreguemos una nueva clase a nuestro TeaListItem.module.css :

    .ImageContainer { position: relative; width: 100%; height: 10em; overflow: hidden;}

    Y luego agreguemos className={styles.ImageContainer}el divque contiene nuestro Image. Utilizo nombres relativamente "simples", porque ImageContainerestamos dentro de un módulo CSS, por lo que no tenemos que preocuparnos de entrar en conflicto con el estilo exterior.

     

    Finalmente, queremos agregar un poco de relleno a los lados del texto, así que agreguemos una última clase y confiemos en las variables de espaciado que configuramos como tokens de diseño:

    .Title { padding-left: var(--space-sm); padding-right: var(--space-sm);}

    Podemos agregar esta clase a la divque contiene nuestro nombre y descripción. Ahora bien, nuestras cartas no tienen tan mala pinta:

    Se muestran tarjetas para 3 tés diferentes que se agregaron como datos de semillas. Tienen imágenes, nombres y descripciones. Actualmente aparecen en una lista vertical sin espacios entre ellos. ( Vista previa grande )

    Combinando estilo global y local

    A continuación, queremos que nuestras tarjetas se muestren en un diseño de cuadrícula. En este caso, estamos justo en la frontera entre los estilos locales y globales. Ciertamente podríamos codificar nuestro diseño directamente en el TeaListcomponente. Pero también podría imaginar que tener una clase de utilidad que convierta una lista en un diseño de cuadrícula podría ser útil en varios otros lugares.

    Tomemos el enfoque global aquí y agreguemos una nueva clase de utilidad en nuestro estilos/utilidades.css :

    .grid { list-style: none; display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--min-item-width, 30ch), 1fr)); gap: var(--space-md);}

    Ahora, podemos agregar la .gridclase a cualquier lista y obtendremos un diseño de cuadrícula que responde automáticamente. También podemos cambiar la --min-item-widthpropiedad personalizada (por defecto 30ch) para cambiar el ancho mínimo de cada elemento.

    Nota : ¡ Recuerde pensar en propiedades personalizadas como accesorios! Si esta sintaxis no le resulta familiar, puede consultar " Cuadrícula CSS intrínsecamente sensible con minmax()ymin() " de Chris Coyier.

    Como hemos escrito este estilo globalmente, no requiere ningún lujo agregarlo className="grid"a nuestro TeaListcomponente. Pero digamos que queremos combinar este estilo global con alguna tienda local adicional. Por ejemplo, queremos incorporar un poco más de la “estética del té” y hacer que todas las demás tarjetas tengan un fondo verde. Todo lo que tendríamos que hacer es crear un nuevo archivo componentes/TeaList/TeaList.module.css :

    .TeaList :nth-child(even) { --color: var(--green);}

    ¿Recuerdas cómo creamos una --color custompropiedad en nuestro TeaListItemcomponente? Bueno, ahora podemos configurarlo bajo circunstancias específicas. Tenga en cuenta que aún podemos usar selectores secundarios dentro de los módulos CSS, y no importa que estemos seleccionando un elemento cuyo estilo esté dentro de un módulo diferente. Entonces, también podemos usar nuestros estilos de componentes locales para afectar los componentes secundarios. ¡Esta es una característica más que un error, ya que nos permite aprovechar la cascada CSS ! Si intentáramos replicar este efecto de otra manera, probablemente terminaríamos con algún tipo de sopa de JavaScript en lugar de tres líneas de CSS.

     

    Entonces, ¿cómo podemos mantener la .gridclase global en nuestro TeaListcomponente y al mismo tiempo agregar la .TeaListclase local? Aquí es donde la sintaxis puede volverse un poco complicada porque tenemos que acceder a nuestra .TeaListclase desde el módulo CSS haciendo algo como style.TeaList.

    Una opción sería utilizar la interpolación de cadenas para obtener algo como:

    ul role="list" className={`${style.TeaList} grid`}

    En este pequeño caso, esto podría ser suficiente. Si mezclamos y combinamos más clases, encuentro que esta sintaxis hace que mi cerebro explote un poco, por lo que a veces opto por usar la biblioteca de nombres de clases. En este caso, terminamos con una lista que parece más sensata:

    ul role="list" className={classnames(style.TeaList, "grid")}

    Ahora hemos terminado nuestra página de Tienda y hemos hecho que nuestro TeaListcomponente aproveche los estilos locales y globales.

    Nuestras tarjetas de té ahora se muestran en una cuadrícula. Los enteros pares son de color verde, mientras que los impares son de color blanco. ( Vista previa grande )

    Un acto de equilibrio

    Ahora hemos construido nuestra tienda de té usando sólo CSS simple para manejar el estilo. Es posible que haya notado que no tuvimos que pasar mucho tiempo lidiando con configuraciones personalizadas de Webpack, instalando bibliotecas externas, etc. Esto se debe a que los patrones que hemos utilizado funcionan con Next.js de forma inmediata. Además, fomentan las mejores prácticas de CSS y encajan de forma natural en la arquitectura del marco Next.js.

    Nuestra organización CSS constaba de cuatro piezas clave:

    1. fichas de diseño,
    2. estilos globales,
    3. Clases de utilidad,
    4. Estilos de componentes.

    A medida que sigamos construyendo nuestro sitio, nuestra lista de tokens de diseño y clases de utilidad crecerá. Cualquier estilo que no tenga sentido agregar como clase de utilidad, podemos agregarlo a los estilos de componentes usando módulos CSS. Como resultado, podemos encontrar un equilibrio continuo entre las preocupaciones de estilo locales y globales. También podemos generar código CSS intuitivo y de alto rendimiento que crece naturalmente junto con nuestro sitio Next.js.

    (vf, yk, il)Explora más en

    • Reaccionar
    • Siguiente.js
    • javascript
    • Marcos





    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Estilo global versus local en Next.js

    Estilo global versus local en Next.js

    Creación y mantenimiento de sistemas de diseño exitosos, con Brad Fost Patrones de diseño de interfaces inteligentes, vídeo de 10h + formación UX Índi

    programar

    es

    https://pseint.es/static/images/programar-estilo-global-versus-local-en-next-1112-0.jpg

    2024-04-04

     

    Estilo global versus local en Next.js
    Estilo global versus local en Next.js

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Top 20