Modal CTA: cómo construir un componente web

 

 

 

  • Anuncie en la revista Smashing
  • Creación y mantenimiento de sistemas de diseño exitosos, con Brad Fost

  • Índice
    1. Incluso antes de comenzar#
  • Utilice la plataforma#
  • Bucear profundo#
    1. Envoltorio condicional#
    2. Variables reutilizables#
    3. Estilos de componentes#
    4. Marcado de componentes#
    5. Constructor#
    6. thisContexto vinculante#
    7. Métodos de ciclo de vida#
    8. Agregar y eliminar eventos#
    9. Detectar cambios de atributos#
    10. Centrándose en elementos específicos#
    11. Detección de modal “exterior”#
    12. Detectar preferencia de movimiento#
    13. Alternar mostrar/ocultar modal#
  • En este artículo, Nathan Smith explica cómo crear ventanas de diálogo modales con interacción rica que solo requerirán la creación de HTML para poder usarse. Se basan en componentes web que actualmente son compatibles con todos los navegadores principales.

     

    Tengo una confesión que hacer: no me gustan demasiado los diálogos modales (o simplemente los “modales”, para abreviar). "Odio" sería una palabra demasiado fuerte para usarla, pero digamos que nada es más desagradable cuando empiezo a leer un artículo que recibir una "bofetada en la cara" con una ventana modal antes de haber comenzado a comprender lo que soy. mirando a.

    O, si pudiera citar a Andy Budd :

    Una visita típica a un sitio web en 2022

    1. Descubra cómo rechazar todas las cookies excepto las esenciales
    2. Cierre el widget de soporte que pregunta si necesito ayuda
    3. Detenga la reproducción automática del vídeo
    4. Cierre la ventana emergente “suscríbase a nuestro boletín informativo”
    5 . Intenta recordar por qué vine aquí en primer lugar.

     

    – Andy Budd (@andybudd) 2 de enero de 2022

    Dicho esto, los modales están en todas partes entre nosotros. Son un paradigma de interfaz de usuario que no podemos simplemente desinventar. Cuando se usan con buen gusto y prudencia , me atrevo a decir que incluso pueden ayudar a agregar más contexto a un documento o a una aplicación.

    A lo largo de mi carrera, he escrito una buena cantidad de modales. He creado implementaciones personalizadas utilizando JavaScript básico, jQuery y, más recientemente, React . Si alguna vez ha tenido dificultades para crear un modal, sabrá a qué me refiero cuando digo: es fácil equivocarse. No sólo desde un punto de vista visual, sino que también hay muchas interacciones complicadas del usuario que deben tenerse en cuenta.

    Soy el tipo de persona a la que le gusta “profundizar” en temas que me molestan, especialmente si encuentro que el tema resurge, con suerte en un esfuerzo por evitar volver a visitarlos nunca más. Cuando comencé a involucrarme más en los componentes web , tuve un "¡ajá!" momento. Ahora que los componentes web son ampliamente compatibles con todos los principales navegadores (RIP, IE11 ), esto abre una nueva puerta de oportunidades. Pensé dentro de mí:

    "¿Qué pasaría si fuera posible crear un modo en el que, como desarrollador que crea una página o aplicación, no tuviera que preocuparme por ninguna configuración de JavaScript adicional?"

    Escribir una vez y correr por todas partes, por así decirlo, o al menos esa era mi elevada aspiración. Buenas noticias. De hecho, es posible crear un modal con interacción rica que solo requiera la creación de HTML para su uso.

    Nota: Para beneficiarse de este artículo y de los ejemplos de código, necesitará algunos conocimientos básicos de HTML, CSS y JavaScript.

    CTA Modal: muestra un formulario. ( Vista previa grande )
    CTA modal: contenido desplazable. ( Vista previa grande )

    Incluso antes de comenzar#

    Si tienes poco tiempo y solo quieres ver el producto terminado, compruébalo aquí:

    • Página de demostración modal de CTA
    • Repositorio modal de CTA en Git

    Utilice la plataforma#

    Ahora que hemos cubierto el “por qué” de rascarse esta picazón en particular, a lo largo del resto de este artículo explicaré el “cómo” de desarrollarla.

    Primero, un curso intensivo rápido sobre componentes web. Son fragmentos empaquetados de HTML, CSS y JavaScript que encapsulan el alcance. Es decir, ningún estilo externo a un componente afectará el interno, ni viceversa. Piense en ello como una “ sala limpia ” herméticamente sellada de diseño de interfaz de usuario.

    A primera vista, esto puede parecer una tontería. ¿Por qué querríamos una parte de la interfaz de usuario que no podemos controlar externamente mediante CSS? Aférrate a ese pensamiento, porque volveremos a él pronto.

    La mejor explicación es la reutilización. Construir un componente de esta manera significa que no estamos en deuda con ningún marco JS en particular del momento . Una frase común que se utiliza en las conversaciones sobre estándares web es " usar la plataforma ". Ahora más que nunca, la plataforma en sí tiene un excelente soporte para varios navegadores .

     

    Bucear profundo#

    Como referencia, me referiré a este ejemplo de código: cta-modal.ts.

    Nota: Estoy usando TypeScript aquí, pero no necesitas ninguna herramienta adicional para crear un componente web. De hecho, escribí mi prueba de concepto inicial en Vanilla JS. Agregué TypeScript más tarde, para reforzar la confianza de otros que lo usan como un paquete NPM.

    El cta-modal.tsarchivo está dividido en varias secciones:

    1. Envoltorio condicional ;
    2. Constantes:
      • variables reutilizables ,
      • estilos de componentes ,
      • Marcado de componentes ;
    3. CtaModalclase:
      • constructora ,
      • thiscontexto vinculante ,
      • métodos de ciclo de vida ,
      • Agregar y eliminar eventos ,
      • Detectar cambios de atributos ,
      • Centrándose en elementos específicos ,
      • Detectando modal “exterior” ,
      • Detectar preferencia de movimiento ,
      • Alternando mostrar/ocultar modal ,
      • Manejar evento: haga clic en superposición ,
      • Manejar evento: haga clic en alternar ,
      • Manejar evento: elemento de enfoque ,
      • Manejar evento: teclado ;
    4. Devolución de llamada cargada DOM :
      • Espera a que la página esté lista,
      • Registra la cta-modaletiqueta.

    Envoltorio condicional#

    Hay un único nivel superior ifque envuelve la totalidad del código del archivo:

    // ===========================// START: if "customElements".// ===========================if ('customElements' in window) { /* NOTE: LINES REMOVED, FOR BREVITY. */}// =========================// END: if "customElements".// =========================

    La razón de esto es doble. Queremos asegurarnos de que el navegador sea compatible con window.customElements. Si es así, esto nos brinda una forma práctica de mantener el alcance variable. Es decir, que al declarar variables mediante consto let, no se “filtran” fuera del if {…}bloque. Mientras que usar una vieja escuela varsería problemático, creando sin darse cuenta varias variables globales.

    Variables reutilizables#

    Nota: Un JavaScript class Foo {…}se diferencia de un HTML o CSS class="foo".

    Piense en ello simplemente como: "Un grupo de funciones agrupadas".

    Esta sección del archivo contiene valores primitivos que pretendo reutilizar en toda mi declaración de clase JS . Destacaré algunos de ellos por ser particularmente interesantes.

     

    // ==========// Constants.// ==========/* NOTE: LINES REMOVED, FOR BREVITY. */const ANIMATION_DURATION = 250;const DATA_HIDE = 'data-cta-modal-hide';const DATA_SHOW = 'data-cta-modal-show';const PREFERS_REDUCED_MOTION = '(prefers-reduced-motion: reduce)';const FOCUSABLE_SELECTORS = [ '[contenteditable]', '[tabindex="0"]:not([disabled])', 'a[href]', 'audio[controls]', 'button:not([disabled])', 'iframe', "input:not([disabled]):not([type='hidden'])", 'select:not([disabled])', 'summary', 'textarea:not([disabled])', 'video[controls]',].join(',');
    • ANIMATION_DURATION
      Especifica cuánto tiempo tardarán mis animaciones CSS. También reutilizo esto más adelante dentro de a setTimeoutpara mantener mi CSS y JS sincronizados. Está configurado en 250milisegundos, que es un cuarto de segundo.
      Mientras que CSS nos permite especificar animation-durationen segundos completos (o milisegundos), JS usa incrementos de milisegundos. Usar este valor me permite usarlo para ambos.
    • DATA_SHOWy DATA_HIDE
      Estas son cadenas para los atributos de datos HTML 'data-cta-modal-show'y 'data-cta-modal-hide'que se utilizan para controlar la visualización/ocultación del modal, así como para ajustar el tiempo de la animación en CSS. Se utilizan más adelante junto con ANIMATION_DURATION.
    • PREFERS_REDUCED_MOTION
      Una consulta de medios que determina si un usuario ha establecido o no la preferencia de su sistema operativo reduceen prefers-reduced-motion. Miro este valor tanto en CSS como en JS para determinar si debo desactivar las animaciones.
    • FOCUSABLE_SELECTORS
      Contiene selectores CSS para todos los elementos que podrían considerarse enfocables dentro de un modal. Se utiliza posteriormente más de una vez, vía querySelectorAll. Lo he declarado aquí para ayudar con la legibilidad, en lugar de agregar desorden al cuerpo de una función.

    Equivale a esta cadena:

    [contenteditable], [tabindex="0"]:not([disabled]), a[href], audio[controls], button:not([disabled]), iframe, input:not([disabled]):not([type='hidden']), select:not([disabled]), summary, textarea:not([disabled]), video[controls]

    Qué asco, ¿verdad? Puedes ver por qué quería dividir eso en varias líneas.

    Como lector astuto, es posible que haya notado type='hidden'y tabindex="0"esté utilizando diferentes comillas. Esto tiene un propósito y revisaremos el razonamiento más adelante.

    Estilos de componentes#

    Esta sección contiene una cadena de varias líneas con una styleetiqueta. Como se mencionó anteriormente, los estilos contenidos en un componente web no afectan al resto de la página. Vale la pena señalar cómo estoy usando variables incrustadas ${etc}mediante interpolación de cadenas.

    • Hacemos referencia a nuestra variable PREFERS_REDUCED_MOTIONpara forzar la configuración de animaciones nonepara los usuarios que prefieren el movimiento reducido.
    • Hacemos referencia DATA_SHOWa y DATA_HIDEjunto con ANIMATION_DURATIONpara permitir el control compartido sobre las animaciones CSS. Tenga en cuenta el uso del mssufijo para milisegundos, ya que es la lengua franca de CSS y JS.
    // ======// Style.// ======const STYLE = ` style /* NOTE: LINES REMOVED, FOR BREVITY. */ @media ${PREFERS_REDUCED_MOTION} { *, *:after, *:before { animation: none !important; transition: none !important; } } [${DATA_SHOW}='true'] .cta-modal__overlay { animation-duration: ${ANIMATION_DURATION}ms; animation-name: SHOW-OVERLAY; } [${DATA_SHOW}='true'] .cta-modal__dialog { animation-duration: ${ANIMATION_DURATION}ms; animation-name: SHOW-DIALOG; } [${DATA_HIDE}='true'] .cta-modal__overlay { animation-duration: ${ANIMATION_DURATION}ms; animation-name: HIDE-OVERLAY; opacity: 0; } [${DATA_HIDE}='true'] .cta-modal__dialog { animation-duration: ${ANIMATION_DURATION}ms; animation-name: HIDE-DIALOG; transform: scale(0.95); } /style`;

    Marcado de componentes#

    El marcado del modal es la parte más sencilla. Estos son los aspectos esenciales que componen el modal:

     

    • ranuras,
    • área desplazable,
    • trampas de enfoque,
    • superposición semitransparente,
    • ventana de diálogo,
    • botón cerrar.

    Cuando se utiliza una cta-modaletiqueta en la página, hay dos puntos de inserción para el contenido. Colocar elementos dentro de estas áreas hace que aparezcan como parte del modal:

    • div slot="button"mapas a slot name='button',
    • div slot="modal"mapas a slot name='modal'.

    Quizás se pregunte qué son las “trampas de enfoque” y por qué las necesitamos. Estos existen para captar el foco cuando un usuario intenta avanzar (o retroceder) fuera del cuadro de diálogo modal. Si cualquiera de estos recibe el foco, volverá a colocar el foco del navegador dentro.

    Además, le damos estos atributos al div que queremos que sirva como nuestro elemento de diálogo modal. Esto le dice al navegador que dives semánticamente significativo. También nos permite poner foco en el elemento vía JS:

    • aria-modal='true',
    • role='dialog',
    • tabindex'-1'.
    // =========// Template.// =========const FOCUS_TRAP = ` span aria-hidden='true' class='cta-modal__focus-trap' tabindex='0' /span`;const MODAL = ` slot name='button'/slot div class='cta-modal__scroll' style='display:none' ${FOCUS_TRAP} div class='cta-modal__overlay' div aria-modal='true' class='cta-modal__dialog' role='dialog' tabindex='-1' button class='cta-modal__close' type='button' ×/button slot name='modal'/slot /div /div ${FOCUS_TRAP} /div`;// Get markup.const markup = [STYLE, MODAL].join(EMPTY_STRING).trim().replace(SPACE_REGEX, SPACE);// Get template.const template = document.createElement(TEMPLATE);template.innerHTML = markup;

    Quizás se pregunte: "¿Por qué no utilizar la dialogetiqueta?" Buena pregunta. Al momento de escribir este artículo, todavía tiene algunas peculiaridades entre navegadores. Para obtener más información al respecto, lea este artículo de Scott O'hara . Además, según la documentación de Mozilla , dialogno está permitido tener un tabindexatributo, por lo que debemos centrarnos en nuestro modal. Blog de Nutricion, Entrenamiento y Fitness

     

    Constructor#

    Cada vez que se crea una instancia de una clase JS, constructorse llama a su función. Ese es sólo un término elegante que significa que se está creando una instancia de la clase. CtaModalEn el caso de nuestro componente web, esta creación de instancias ocurre automáticamente cada vez que cta-modalse encuentra un en el HTML de una página.

    Dentro de constructorwe call super, le dice a la HTMLElementclase (que estamos extend-ing) que llame a su propia constructor. Piense en ello como un código adhesivo, para asegurarnos de que aprovechamos algunos de los métodos predeterminados del ciclo de vida.

    A continuación, llamamos this._bind()al que cubriremos un poco más más adelante. Luego adjuntamos el "DOM sombra" a nuestra instancia de clase y agregamos el marcado que creamos como una cadena multilínea anteriormente.

    Después de eso, obtenemos todos los elementos, desde la sección de marcado de componentes antes mencionada , para usarlos en llamadas a funciones posteriores. Por último, llamamos a algunos métodos auxiliares que leen atributos de la cta-modaletiqueta correspondiente.

    // =======================// Lifecycle: constructor.// =======================constructor() { // Parent constructor. super(); // Bind context. this._bind(); // Shadow DOM. this._shadow = this.attachShadow({ mode: 'closed' }); // Add template. this._shadow.appendChild( // Clone node. template.content.cloneNode(true) ); // Get slots. this._slotForButton = this.querySelector("[slot='button']"); this._slotForModal = this.querySelector("[slot='modal']"); // Get elements. this._heading = this.querySelector('h1, h2, h3, h4, h5, h6'); // Get shadow elements. this._buttonClose = this._shadow.querySelector('.cta-modal__close') as HTMLElement; this._focusTrapList = this._shadow.querySelectorAll('.cta-modal__focus-trap'); this._modal = this._shadow.querySelector('.cta-modal__dialog') as HTMLElement; this._modalOverlay = this._shadow.querySelector('.cta-modal__overlay') as HTMLElement; this._modalScroll = this._shadow.querySelector('.cta-modal__scroll') as HTMLElement; // Missing slot? if (!this._slotForModal) { window.console.error('Required [slot="modal"] not found inside cta-modal.'); } // Set animation flag. this._setAnimationFlag(); // Set close title. this._setCloseTitle(); // Set modal label. this._setModalLabel(); // Set static flag. this._setStaticFlag(); /* ===== NOTE: ===== We set this flag last because the UI visuals within are contingent on some of the other flags being set. */ // Set active flag. this._setActiveFlag();}

    thisContexto vinculante#

    Esto es un poco de magia de JS que nos evita tener que escribir código tedioso innecesariamente en otros lugares. Cuando se trabaja con eventos DOM, el contexto thispuede cambiar, dependiendo del elemento con el que se interactúa dentro de la página.

    Una forma de garantizar que thissiempre signifique la instancia de nuestra clase es llamar específicamente a bind. Básicamente, esta función hace que se maneje automáticamente. Eso significa que no tenemos que escribir cosas como esta en todas partes.

     

    /* NOTE: Just an example, we don't need this. */this.someFunctionName1 = this.someFunctionName1.bind(this);this.someFunctionName2 = this.someFunctionName2.bind(this);

    En lugar de escribir el fragmento anterior, cada vez que agregamos una nueva función, una this._bind()llamada útil se constructorencarga de todas las funciones que podamos tener. Este bucle toma cada propiedad de clase que es a functiony la vincula automáticamente.

    // ============================// Helper: bind `this` context.// ============================_bind() { // Get property names. const propertyNames = Object.getOwnPropertyNames( // Get prototype. Object.getPrototypeOf(this) ) as (keyof CtaModal)[]; // Loop through. propertyNames.forEach((name) = { // Bind functions. if (typeof this[name] === FUNCTION) { /* ===== NOTE: ===== Why use "@ts-expect-error" here? Calling `*.bind(this)` is a standard practice when using JavaScript classes. It is necessary for functions that might change context because they are interacting directly with DOM elements. Basically, I am telling TypeScript: "Let me live my life!" */ // @ts-expect-error bind this[name] = this[name].bind(this); } });}

    Métodos de ciclo de vida#

    Por la naturaleza de esta línea, de donde somos extend, HTMLElementrecibimos algunas llamadas a funciones integradas de forma "gratuita". Siempre que nombremos nuestras funciones con estos nombres, se llamarán en el momento apropiado dentro del ciclo de vida de nuestro cta-modalcomponente.

    // ==========// Component.// ==========class CtaModal extends HTMLElement { /* NOTE: LINES REMOVED, FOR BREVITY. */}
    • observedAttributes
      Esto le dice al navegador qué atributos estamos observando en busca de cambios.
    • attributeChangedCallback
      Si alguno de esos atributos cambia, se invocará esta devolución de llamada. Dependiendo del atributo que cambió, llamamos a una función para leer el atributo.
    • connectedCallback
      Esto se llama cuando cta-modalse registra una etiqueta en la página. Aprovechamos esta oportunidad para agregar todos nuestros controladores de eventos.
      Si está familiarizado con React , esto es similar al componentDidMountevento del ciclo de vida.
    • disconnectedCallback
      Esto se llama cuando cta-modalse elimina una etiqueta de la página. Del mismo modo, eliminamos todos los controladores de eventos obsoletos cuando esto ocurre.
      Es similar al componentWillUnmountevento del ciclo de vida en React.

    Nota: Vale la pena señalar que estas son las únicas funciones dentro de nuestra clase que no tienen el prefijo de guión bajo ( _). Aunque no es estrictamente necesario, la razón es doble. Primero, hace obvio qué funciones hemos creado para nuestra nueva clase cta-modaly cuáles son eventos nativos del ciclo de vida de la HTMLElementclase. Dos, cuando minimizamos nuestro código más adelante, el prefijo indica que pueden ser destruidos. Mientras que los métodos nativos del ciclo de vida deben conservar sus nombres palabra por palabra.

     

    // ============================// Lifecycle: watch attributes.// ============================static get observedAttributes() { return [ACTIVE, ANIMATED, CLOSE, STATIC];}// ==============================// Lifecycle: attributes changed.// ==============================attributeChangedCallback(name: string, oldValue: string, newValue: string) { // Different old/new values? if (oldValue !== newValue) { // Changed [active="…"] value? if (name === ACTIVE) { this._setActiveFlag(); } // Changed [animated="…"] value? if (name === ANIMATED) { this._setAnimationFlag(); } // Changed [close="…"] value? if (name === CLOSE) { this._setCloseTitle(); } // Changed [static="…"] value? if (name === STATIC) { this._setStaticFlag(); } }}// ===========================// Lifecycle: component mount.// ===========================connectedCallback() { this._addEvents();}// =============================// Lifecycle: component unmount.// =============================disconnectedCallback() { this._removeEvents();}

    Agregar y eliminar eventos#

    Estas funciones registran (y eliminan) devoluciones de llamada para varios elementos y eventos a nivel de página:

    • botones presionados,
    • elementos enfocados,
    • teclado presionado,
    • se hizo clic en la superposición.
    // ===================// Helper: add events.// ===================_addEvents() { // Prevent doubles. this._removeEvents(); document.addEventListener(FOCUSIN, this._handleFocusIn); document.addEventListener(KEYDOWN, this._handleKeyDown); this._buttonClose.addEventListener(CLICK, this._handleClickToggle); this._modalOverlay.addEventListener(CLICK, this._handleClickOverlay); if (this._slotForButton) { this._slotForButton.addEventListener(CLICK, this._handleClickToggle); this._slotForButton.addEventListener(KEYDOWN, this._handleClickToggle); } if (this._slotForModal) { this._slotForModal.addEventListener(CLICK, this._handleClickToggle); this._slotForModal.addEventListener(KEYDOWN, this._handleClickToggle); }}// ======================// Helper: remove events.// ======================_removeEvents() { document.removeEventListener(FOCUSIN, this._handleFocusIn); document.removeEventListener(KEYDOWN, this._handleKeyDown); this._buttonClose.removeEventListener(CLICK, this._handleClickToggle); this._modalOverlay.removeEventListener(CLICK, this._handleClickOverlay); if (this._slotForButton) { this._slotForButton.removeEventListener(CLICK, this._handleClickToggle); this._slotForButton.removeEventListener(KEYDOWN, this._handleClickToggle); } if (this._slotForModal) { this._slotForModal.removeEventListener(CLICK, this._handleClickToggle); this._slotForModal.removeEventListener(KEYDOWN, this._handleClickToggle); }}
    • Leverage robust data-fetching and optimized bundle size with the KendoReact Server Data Grid Try now

    Detectar cambios de atributos#

    Estas funciones manejan la lectura de atributos de una cta-modaletiqueta y, como resultado, configuran varios indicadores:

     

    • Establecer un _isAnimatedvalor booleano en nuestra instancia de clase.
    • Configuración titley aria-labelatributos en nuestro botón de cerrar.
    • Estableciendo un aria-labelpara nuestro diálogo modal, basado en el texto del encabezado.
    • Establecer un _isActivevalor booleano en nuestra instancia de clase.
    • Establecer un _isStaticvalor booleano en nuestra instancia de clase.

    Quizás se pregunte por qué utilizamos aria-labelpara relacionar el modal con el texto de su encabezado (si existe). Al momento de escribir este artículo, los navegadores no pueden actualmente correlacionar un aria-labelledby="…"atributo (dentro del DOM oculto) con uno id="…"ubicado en el DOM estándar (también conocido como "ligero").

    No entraré en muchos detalles sobre eso, pero puedes leer más aquí:

    • W3C: ARIA de raíz cruzada
    • WHATWG: ticket de reflexión de elemento
    // ===========================// Helper: set animation flag.// ===========================_setAnimationFlag() { this._isAnimated = this.getAttribute(ANIMATED) !== FALSE;}// =======================// Helper: add close text.// =======================_setCloseTitle() { // Get title. const title = this.getAttribute(CLOSE) || CLOSE_TITLE; // Set title. this._buttonClose.title = title; this._buttonClose.setAttribute(ARIA_LABEL, title);}// ========================// Helper: add modal label.// ========================_setModalLabel() { // Set later. let label = MODAL_LABEL_FALLBACK; // Heading exists? if (this._heading) { // Get text. label = this._heading.textContent || label; label = label.trim().replace(SPACE_REGEX, SPACE); } // Set label. this._modal.setAttribute(ARIA_LABEL, label);}// ========================// Helper: set active flag.// ========================_setActiveFlag() { // Get flag. const isActive = this.getAttribute(ACTIVE) === TRUE; // Set flag. this._isActive = isActive; // Set display. this._toggleModalDisplay(() = { // Focus modal? if (this._isActive) { this._focusModal(); } });}// ========================// Helper: set static flag.// ========================_setStaticFlag() { this._isStatic = this.getAttribute(STATIC) === TRUE;}

    Centrándose en elementos específicos#

    La _focusElementfunción nos permite enfocar un elemento que puede haber estado activo antes de que un modal se activara. Mientras que la _focusModalfunción se centrará en el cuadro de diálogo modal en sí y garantizará que el fondo modal se desplace hacia la parte superior.

    // ======================// Helper: focus element.// ======================_focusElement(element: HTMLElement) { window.requestAnimationFrame(() = { if (typeof element.focus === FUNCTION) { element.focus(); } });}// ====================// Helper: focus modal.// ====================_focusModal() { window.requestAnimationFrame(() = { this._modal.focus(); this._modalScroll.scrollTo(0, 0); });}

    Detección de modal “exterior”#

    Esta función es útil para saber si un elemento reside fuera de la cta-modaletiqueta principal. Devuelve un valor booleano, que podemos utilizar para realizar las acciones adecuadas. Es decir, la pestaña captura la navegación dentro del modal mientras está activo.

    // =============================// Helper: detect outside modal.// =============================_isOutsideModal(element?: HTMLElement) { // Early exit. if (!this._isActive || !element) { return false; } // Has element? const hasElement = this.contains(element) || this._modal.contains(element); // Get boolean. const bool = !hasElement; // Expose boolean. return bool;}

    Detectar preferencia de movimiento#

    Aquí, reutilizamos nuestra variable anterior (también utilizada en nuestro CSS) para detectar si un usuario está de acuerdo con el movimiento. Es decir, no lo han configurado explícitamente prefers-reduced-motiona reducetravés de las preferencias de su sistema operativo.

    El booleano devuelto es una combinación de esa verificación, más el animated="false"indicador que no está activado cta-modal.

    // ===========================// Helper: detect motion pref.// ===========================_isMotionOkay() { // Get pref. const { matches } = window.matchMedia(PREFERS_REDUCED_MOTION); // Expose boolean. return this._isAnimated !matches;}

    Alternar mostrar/ocultar modal#

    Hay muchas cosas que hacer en esta función, pero en esencia, es bastante simple.

    • Si el modal no está activo, muéstralo. Si se permite la animación, anímela en su lugar.
    • Si el modal está activo, escóndelo. Si se permite la animación, anímela desapareciendo.

    También almacenamos en caché el elemento actualmente activo, de modo que cuando se cierre el modal podamos restaurar el foco.

    Las variables utilizadas anteriormente en nuestro CSS también se utilizan aquí:

    Modal CTA: cómo construir un componente web

    Modal CTA: cómo construir un componente web

    Anuncie en la revista Smashing Creación y mantenimiento de sistemas de diseño exitosos, con Brad Fost Índice

    programar

    es

    https://aprendeprogramando.es/static/images/programar-modal-cta-como-construir-un-componente-web-1139-0.jpg

    2024-04-04

     

    Modal CTA: cómo construir un componente web
    Modal CTA: cómo construir un componente web

    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