Reaccionar: ¿Mostrar la pantalla de carga mientras se procesa DOM?

150

Este es un ejemplo de la página de la aplicación Google Adsense. La pantalla de carga mostrada antes de la página principal mostrada después.

ingrese la descripción de la imagen aquí

No sé cómo hacer lo mismo con React porque si hago que la pantalla de carga sea procesada por el componente React, no se muestra mientras se carga la página porque tiene que esperar a que DOM se procese antes.

Actualizado :

Hice un ejemplo de mi enfoque al poner el cargador de pantalla index.htmly eliminarlo en el componentDidMount()método React lifecycle.

Ejemplo y reaccionar-cargar-pantalla .

Thanh Nguyen
fuente
Muestre lo que desea mostrar en js simple, luego oculte o elimine del DOM cuando haya reaccionado. Todo lo que necesitas hacer es ocultarlo del código de reacción.
FurkanO
¡Esto es simplemente maravilloso! Gracias.
Arman Karimi

Respuestas:

100

Esto se puede hacer colocando el ícono de carga en su archivo html (index.html para ej.), De modo que los usuarios vean el ícono inmediatamente después de cargar el archivo html.

Cuando su aplicación termina de cargarse, simplemente puede eliminar ese ícono de carga en un enlace de ciclo de vida, generalmente lo hago en componentDidMount.

kkkkkkk
fuente
11
Si monta el componente raíz en el nodo primario de ese icono, ni siquiera es necesario eliminarlo manualmente. React limpiará los hijos del nodo de montaje y colocará allí su propio DOM recién renderizado.
rishat
66
No pongo el ícono dentro del nodo raíz de la aplicación React, simplemente no me parece correcto
kkkkkkk
171

La meta

Cuando se procese la página html, muestre una rueda giratoria inmediatamente (mientras React carga) y escóndela después de que React esté listo.

Dado que la ruleta se representa en HTML / CSS puro (fuera del dominio React), React no debe controlar el proceso de mostrar / ocultar directamente, y la implementación debe ser transparente para React.

Solución 1 - la: pseudo-clase vacía

Como renderizas reaccionas en un contenedor DOM - <div id="app"></div> , puede agregar una ruleta a ese contenedor, y cuando reaccione se cargará y procesará, la ruleta desaparecerá.

No puede agregar un elemento DOM (un div por ejemplo) dentro de la raíz de reacción, ya que React reemplazará el contenido del contenedor tan pronto como ReactDOM.render()se llame. Incluso si procesa null, el contenido aún sería reemplazado por un comentario <!-- react-empty: 1 -->. Esto significa que si desea mostrar el cargador mientras se monta el componente principal, los datos se están cargando, pero en realidad no se muestra nada, se coloca una marca del cargador dentro del contenedor (<div id="app"><div class="loader"></div></div> por ejemplo) no funcionaría.

Una solución alternativa es agregar la clase spinner al contenedor de reacción y usar la :emptypseudo clase . La ruleta estará visible, siempre que no se muestre nada en el contenedor (los comentarios no cuentan). Tan pronto como reacciona representa algo más que comentario, el cargador desaparecerá.

Ejemplo 1

En el ejemplo, puede ver un componente que se procesa nullhasta que esté listo. El contenedor también es el cargador <div id="app" class="app"></div>, y la clase del cargador solo funcionará si es así :empty(ver comentarios en el código):

Ejemplo 2

Una variación sobre el uso de la :emptypseudo clase para mostrar / ocultar un selector, es configurar la ruleta como un elemento hermano para el contenedor de la aplicación, y mostrarla siempre que el contenedor esté vacío usando el combinador de hermanos adyacente ( +):


Solución 2 - Pase los "controladores" de la ruleta como accesorios

Para tener un control más grano fino sobre el estado de visualización hiladores, crear dos funciones showSpinnery hideSpinner, y pasarlas al contenedor raíz a través de los apoyos. Las funciones pueden manipular el DOM o hacer lo que sea necesario para controlar la ruleta. De esta manera, React no es consciente del "mundo exterior", ni necesita controlar el DOM directamente. Puede reemplazar fácilmente las funciones para la prueba, o si necesita cambiar la lógica, y puede pasarlas a otros componentes en el árbol React.

Ejemplo 1

Ejemplo 2 - ganchos

Este ejemplo usa el useEffectgancho para ocultar la ruleta después de que se monte el componente.

Ori Drori
fuente
¿Podría aclarar dónde deberían estar las últimas 2 secciones de código? El primero está claramente en el archivo src de javascript para el componente de reacción, el tercero, supongo, va en la plantilla html para ser representada por dicho archivo js, ​​pero ¿a dónde va el segundo?
levraininjaneer
1
El segundo es el CSS. He usado CSS global, pero puedes usar módulos CSS o CSS en JS. El tercero es el archivo HTML, que puede incluir marcado de la rueda giratoria si es necesario (segundo ejemplo).
Ori Drori
Ese tiempo de espera no es bueno cuando se tiene en cuenta el rendimiento.
dryleaf
44
@dryleaf: setTimeout no es parte de la solución. Simula esperar una acción asincrónica antes de representar el contenido.
Ori Drori el
Yo uso un enfoque similar. No puedo encontrar nada en el paquete web que pueda ayudarme a reventar el caché para el archivo CSS requerido para el cargador. ¿Puede usted ayudar?
hamza-jutt
40

La solución para esto es:

En su función de render, haga algo como esto:

constructor() {
    this.state = { isLoading: true }
}

componentDidMount() {
    this.setState({isLoading: false})
}

render() {
    return(
        this.state.isLoading ? *showLoadingScreen* : *yourPage()*
    )
}

Inicializar isLoading como verdadero en el constructor y falso en componentDidMount

Amoolya S Kumar
fuente
Cuando hemos llamado al método ajax para cargar datos a los componentes secundarios. Se llama a componentDidMount antes de que se llenen los datos del componente hijo ¿Cómo superamos este tipo de problema?
dush88c
2
Para el montaje del ciclo de vida está bien, ¿le gustaría agregar algo para actualizar el ciclo de vida?
zakir
¿Tengo que hacer esto en todas las páginas o solo en la entrada de la aplicación
Pedro JR
16

Si alguien busca una biblioteca de acceso directo, configuración cero y dependencias cero para el caso de uso anterior, intente pace.js ( http://github.hubspot.com/pace/docs/welcome/ ).

Se conecta automáticamente a eventos (ajax, readyState, historial de estado, bucle de eventos js, etc.) y muestra un cargador personalizable.

Funcionó bien con nuestros proyectos de reacción / retransmisión (maneja los cambios de navegación usando react-router, solicitudes de retransmisión) (No afiliado; había usado pace.js para nuestros proyectos y funcionó muy bien)

Hafiz Ismail
fuente
¡Oye! ¿Me puede decir cómo usarlo con react?
uneet7
simplemente adjunte el script public/index.htmly elija un estilo. Este es un complemento increíblemente simple. gracias.
PJ3
No habría encontrado el ritmo sin esta respuesta. Fue muy fácil de incluir, y con un poco de magia CSS y algunos archivos adjuntos de eventos pude bloquear / deshabilitar la aplicación durante las transiciones y personalizar el spinner.
invertedSpear
12

Cuando su aplicación React es masiva, realmente toma tiempo para que se ponga en funcionamiento después de que se haya cargado la página. Digamos que montas tu parte React de la aplicación #app. Por lo general, este elemento en su index.html es simplemente un div vacío:

<div id="app"></div>

Lo que puedes hacer es poner un poco de estilo y un montón de imágenes allí para que se vea mejor entre la carga de la página y el renderizado inicial de la aplicación React a DOM:

<div id="app">
  <div class="logo">
    <img src="/my/cool/examplelogo.svg" />
  </div>
  <div class="preload-title">
    Hold on, it's loading!
  </div>
</div>

Después de cargar la página, el usuario verá inmediatamente el contenido original de index.html. Poco después, cuando React esté listo para montar toda la jerarquía de componentes renderizados en este nodo DOM, el usuario verá la aplicación real.

Nota classno className. Es porque necesita poner esto en su archivo html.


Si usa SSR, las cosas son menos complicadas porque el usuario realmente verá la aplicación real justo después de que se cargue la página.

rishat
fuente
Esto funciona también tengo dos lugares donde ocurre la carga. Una es la aplicación masiva. y luego está la preparación (montaje de varios componentes). Así que obtengo un paso intermitente porque la aplicación.render se hace cargo y la animación se reinicia ( reemplaza realmente). ¿Habría alguna forma de evitar ese destello? ¿Reaccionará comparar el DOM uno a uno? Pero por lo que entiendo, React agrega todo tipo de datos privados en las etiquetas ...
Alexis Wilke
12

Esto sucederá antes de ReactDOM.render()tomar el control de la raíz <div> . Es decir, su aplicación no se habrá montado hasta ese punto.

Para que pueda agregar su cargador en su index.htmlarchivo dentro de la raíz <div>. Y eso será visible en la pantalla hasta que React se haga cargo.

Puede usar cualquier elemento del cargador que funcione mejor para usted ( svgcon animación, por ejemplo).

No es necesario eliminarlo en ningún método de ciclo de vida. React reemplazará cualquier elemento secundario de su raíz <div> con su renderizado <App/>, como podemos ver en el GIF a continuación.

Ejemplo en CodeSandbox

ingrese la descripción de la imagen aquí

index.html

<head>
  <style>
    .svgLoader {
      animation: spin 0.5s linear infinite;
      margin: auto;
    }
    .divLoader {
      width: 100vw;
      height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    @keyframes spin {
      0% { transform: rotate(0deg); }
      100% { transform: rotate(360deg); }
    }
  </style>
</head>

<body>
  <div id="root">
    <div class="divLoader">
      <svg class="svgLoader" viewBox="0 0 1024 1024" width="10em" height="10em">
        <path fill="lightblue"
          d="PATH FOR THE LOADER ICON"
        />
      </svg>
    </div>
  </div>
</body>

index.js

Utilizando debuggerpara inspeccionar la página antes de ReactDOM.render()ejecutar.

import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";

function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

debugger; // TO INSPECT THE PAGE BEFORE 1ST RENDER

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
cbdeveloper
fuente
una solución hermosa y elegante
Gal Margalit
1
¡Me alegra que ayude!
cbdeveloper
9

Hoy en día también podemos usar ganchos en React 16.8:

import React, { useState, useEffect } from 'react';

const App = () => {
  const [ spinner, setSpinner ] = useState(true);

  // It will be executed before rendering

  useEffect(() => {
    setTimeout(() => setSpinner(false), 1000)
  }, []);

  // [] means like componentDidMount

  return !spinner && <div>Your content</div>;
};

export default App;
Max Kalik
fuente
5

Establecer el tiempo de espera en componentDidMount funciona pero en mi aplicación recibí una advertencia de pérdida de memoria. Intenta algo como esto.

constructor(props) {
    super(props)
    this.state = { 
      loading: true,
    }
  }
  componentDidMount() {
    this.timerHandle = setTimeout(() => this.setState({ loading: false }), 3500); 
  }

  componentWillUnmount(){
    if (this.timerHandle) {
      clearTimeout(this.timerHandle);
      this.timerHandle = 0;
    }
  }
Rich Costello
fuente
4

Tuve que lidiar con ese problema recientemente y se me ocurrió una solución, que funciona bien para mí. Sin embargo, probé la solución @Ori Drori anterior y desafortunadamente no funcionó correctamente (tuve algunos retrasos + No me gusta el uso desetTimeout función allí).

Esto es lo que se me ocurrió:

index.html expediente

headEtiqueta interior : estilos para el indicador:

<style media="screen" type="text/css">

.loading {
  -webkit-animation: sk-scaleout 1.0s infinite ease-in-out;
  animation: sk-scaleout 1.0s infinite ease-in-out;
  background-color: black;
  border-radius: 100%;
  height: 6em;
  width: 6em;
}

.container {
  align-items: center;
  background-color: white;
  display: flex;
  height: 100vh;
  justify-content: center;
  width: 100vw;
}

@keyframes sk-scaleout {
  0% {
    -webkit-transform: scale(0);
    transform: scale(0);
  }
  100% {
    -webkit-transform: scale(1.0);
    opacity: 0;
    transform: scale(1.0);
  }
}

</style>

Ahora la bodyetiqueta:

<div id="spinner" class="container">
  <div class="loading"></div>
</div>

<div id="app"></div>

Y luego viene una lógica muy simple, dentro del app.jsarchivo (en la función de renderizado):

const spinner = document.getElementById('spinner');

if (spinner && !spinner.hasAttribute('hidden')) {
  spinner.setAttribute('hidden', 'true');
}

Como funciona

Cuando el primer componente (en mi aplicación también lo es app.jsen la mayoría de los casos) se monta correctamente, spinnerse oculta con la aplicaciónhidden atributos.

Lo que es más importante agregar: la !spinner.hasAttribute('hidden')condición impide agregar hiddenatributos al spinner con cada montaje de componentes, por lo que en realidad se agregará solo una vez, cuando se cargue toda la aplicación.

usuario amable
fuente
4

Estoy usando el paquete react-progress-2 npm, que es de dependencia cero y funciona muy bien en ReactJS.

https://github.com/milworm/react-progress-2

Instalación:

npm install react-progress-2

Incluya react-progress-2 / main.css a su proyecto.

import "node_modules/react-progress-2/main.css";

Incluya react-progress-2y colóquelo en algún lugar del componente superior, por ejemplo:

import React from "react";
import Progress from "react-progress-2";

var Layout = React.createClass({
render: function() {
    return (
        <div className="layout">
            <Progress.Component/>
                {/* other components go here*/}
            </div>
        );
    }
});

Ahora, cuando necesite mostrar un indicador, simplemente llame Progress.show(), por ejemplo:

loadFeed: function() {
    Progress.show();
    // do your ajax thing.
},

onLoadFeedCallback: function() {
    Progress.hide();
    // render feed.
}

Tenga en cuenta, que los showy hidelas llamadas se apilan, por lo que después-n consecutiva muestran las llamadas, lo que necesita hacer llamadas n Ocultar para ocultar un indicador o puede utilizar Progress.hideAll().

Alex Zavrazhniy
fuente
4

También estoy usando React en mi aplicación. Para las solicitudes que estoy usando los interceptores axios, una excelente manera de hacer la pantalla del cargador (página completa como mostraste un ejemplo) es agregar clase o id a, por ejemplo, el cuerpo dentro de los interceptores (aquí el código de la documentación oficial con algún código personalizado):

// Add a request interceptor
axios.interceptors.request.use(function (config) {
    // Do something before request is sent
     document.body.classList.add('custom-loader');
     return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });

// Add a response interceptor
axios.interceptors.response.use(function (response) {
    // Do something with response data
       document.body.classList.remove('custom-loader');
       return response;
  }, function (error) {
    // Do something with response error
    return Promise.reject(error);
  }); 

Y luego simplemente implemente en CSS su cargador con pseudo-elementos (o agregue clase o id a un elemento diferente, no el cuerpo como desee): puede establecer el color de fondo en opaco o transparente, etc. Ejemplo:

custom-loader:before {
    background: #000000;
    content: "";
    position: fixed;
    ...
}

custom-loader:after {
    background: #000000;
    content: "Loading content...";
    position: fixed;
    color: white;
    ...
}
adrian95999
fuente
3

Edite la ubicación de su archivo index.html en la carpeta pública . Copie su imagen en la misma ubicación que index.html en la carpeta pública. Y luego reemplace la parte del contenido de index.html que contiene <div id="root"> </div>etiquetas por el siguiente código html dado.

<div id="root">  <img src="logo-dark300w.png" alt="Spideren" style="vertical-align: middle; position: absolute;
   top: 50%;
   left: 50%;
   margin-top: -100px; /* Half the height */
   margin-left: -250px; /* Half the width */" />  </div>

El logotipo ahora aparecerá en el medio de la página durante el proceso de carga. Y luego será reemplazado después de unos segundos por React.

Magnus Melwin
fuente
2

No necesita tanto esfuerzo, aquí hay un ejemplo básico.

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
  <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="theme-color" content="#000000" />
  <meta name="description" content="Web site created using create-react-app" />
  <link rel="apple-touch-icon" href="logo192.png" />
  <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
  <title>Title</title>
  <style>
    body {
      margin: 0;
    }

    .loader-container {
      width: 100vw;
      height: 100vh;
      display: flex;
      overflow: hidden;
    }

    .loader {
      margin: auto;
      border: 5px dotted #dadada;
      border-top: 5px solid #3498db;
      border-radius: 50%;
      width: 100px;
      height: 100px;
      -webkit-animation: spin 2s linear infinite;
      animation: spin 2s linear infinite;
    }

    @-webkit-keyframes spin {
      0% {
        -webkit-transform: rotate(0deg);
      }

      100% {
        -webkit-transform: rotate(360deg);
      }
    }

    @keyframes spin {
      0% {
        transform: rotate(0deg);
      }

      100% {
        transform: rotate(360deg);
      }
    }

  </style>
</head>

<body>
  <noscript>You need to enable JavaScript to run this app.</noscript>
  <div id="root">
    <div class="loader-container">
      <div class="loader"></div>
    </div>
  </div>
</body>

</html>

Puedes jugar HTMLy CSShacer que se vea como tu ejemplo.

Ahmed Kamal
fuente
1

La pregunta más importante es: ¿qué quiere decir con "carga"? Si está hablando del elemento físico que se está montando, algunas de las primeras respuestas aquí son geniales. Sin embargo, si lo primero que hace su aplicación es verificar la autenticación, lo que realmente está cargando son datos del backend si el usuario pasó una cookie que los etiqueta como usuarios autorizados o no autorizados.

Esto se basa en redux, pero puede cambiarlo fácilmente al modelo de estado de reacción simple.

creador de acción:

export const getTodos = () => {
  return async dispatch => {
    let res;
    try {
      res = await axios.get('/todos/get');

      dispatch({
        type: AUTH,
        auth: true
      });
      dispatch({
        type: GET_TODOS,
        todos: res.data.todos
      });
    } catch (e) {
    } finally {
      dispatch({
        type: LOADING,
        loading: false
      });
    }
  };
};

La parte final significa si el usuario está autenticado o no, la pantalla de carga desaparece después de recibir una respuesta.

Así es como se vería un componente que lo carga:

class App extends Component {
  renderLayout() {
    const {
      loading,
      auth,
      username,
      error,
      handleSidebarClick,
      handleCloseModal
    } = this.props;
    if (loading) {
      return <Loading />;
    }
    return (
      ...
    );
  }

  ...

  componentDidMount() {
    this.props.getTodos();
  }

...

  render() {
    return this.renderLayout();
 }

}

Si state.loading es verdadero, siempre veremos una pantalla de carga. En componentDidMount, llamamos a nuestra función getTodos, que es un creador de acciones que convierte el estado en carga falsa cuando recibimos una respuesta (que puede ser un error). Nuestras actualizaciones de componentes, las llamadas se procesan nuevamente, y esta vez no hay pantalla de carga debido a la declaración if.

usuario3605834
fuente
1

El inicio de la aplicación Reaccionar se basa en la descarga del paquete principal. La aplicación React solo comienza después de que el paquete principal se descarga en el navegador. Esto es incluso cierto en el caso de la arquitectura de carga diferida. Pero el hecho es que no podemos decir exactamente el nombre de ningún paquete. Debido a que webpack agregará un valor hash al final de cada paquete en el momento en que ejecute el comando 'npm run build'. Por supuesto, podemos evitar eso cambiando la configuración de hash, pero afectará seriamente el problema de los datos de caché en el navegador. Es posible que los navegadores no tomen la nueva versión debido al mismo nombre de paquete. . Necesitamos un enfoque webpack + js + CSS para manejar esta situación.

cambie public / index.html como se muestra a continuación

<!DOCTYPE html>
<html lang="en" xml:lang="en">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=3.0, shrink-to-fit=no">
  <meta name="theme-color" content="#000000">
  <!--
      manifest.json provides metadata used when your web app is added to the
      homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
    -->
  <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
  <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
  <style>
 .percentage {
      position: absolute;
      top: 50%;
      left: 50%;
      width: 150px;
      height: 150px;
      border: 1px solid #ccc;
      background-color: #f3f3f3;
      -webkit-transform: translate(-50%, -50%);
          -ms-transform: translate(-50%, -50%);
              transform: translate(-50%, -50%);
      border: 1.1em solid rgba(0, 0, 0, 0.2);
      border-radius: 50%;
      overflow: hidden;
      display: -webkit-box;
      display: -ms-flexbox;
      display: flex;
      -webkit-box-pack: center;
          -ms-flex-pack: center;
              justify-content: center;
      -webkit-box-align: center;
          -ms-flex-align: center;
              align-items: center;
    }

    .innerpercentage {
      font-size: 20px;
    }
  </style>
  <script>
    function showPercentage(value) {
      document.getElementById('percentage').innerHTML = (value * 100).toFixed() + "%";
    }
    var req = new XMLHttpRequest();
    req.addEventListener("progress", function (event) {
      if (event.lengthComputable) {
        var percentComplete = event.loaded / event.total;
        showPercentage(percentComplete)
        // ...
      } else {
        document.getElementById('percentage').innerHTML = "Loading..";
      }
    }, false);

    // load responseText into a new script element
    req.addEventListener("load", function (event) {
      var e = event.target;
      var s = document.createElement("script");
      s.innerHTML = e.responseText;
      document.documentElement.appendChild(s);
      document.getElementById('parentDiv').style.display = 'none';

    }, false);

    var bundleName = "<%= htmlWebpackPlugin.files.chunks.main.entry %>";
    req.open("GET", bundleName);
    req.send();

  </script>
  <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->

  <title>App Name</title>
  <link href="<%= htmlWebpackPlugin.files.chunks.main.css[0] %>" rel="stylesheet">
</head>

<body>
  <noscript>
    You need to enable JavaScript to run this app.
  </noscript>
  <div id="parentDiv" class="percentage">
    <div id="percentage" class="innerpercentage">loading</div>
  </div>
  <div id="root"></div>
  <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
</body>

</html>

En la configuración de su paquete web de producción, cambie la opción HtmlWebpackPlugin a continuación

 new HtmlWebpackPlugin({
          inject: false,
...

Es posible que necesite usar el comando 'expulsar' para obtener el archivo de configuración. El último paquete web podría tener la opción de configurar HtmlWebpackPlugin sin expulsar el proyecto. ingrese la descripción de la imagen aquí

Anoop Chillayi Kochappu
fuente
1

También utilicé la respuesta de @Ori Drori y logré que funcionara. A medida que crezca su código React, también lo harán los paquetes compilados que el navegador del cliente tendrá que descargar en el acceso por primera vez. Esto impone un problema de experiencia del usuario si no lo manejas bien.

Lo que agregué a @Ori answer fue agregar y ejecutar la función onload en el atributo index.html on onload de la etiqueta del cuerpo, para que el cargador desaparezca después de que todo se haya cargado completamente en la exploración, vea el fragmento a continuación:

<html>
  <head>
     <style>
       .loader:empty {
          position: absolute;
          top: calc(50% - 4em);
          left: calc(50% - 4em);
          width: 6em;
          height: 6em;
          border: 1.1em solid rgba(0, 0, 0, 0.2);
          border-left: 1.1em solid #000000;
          border-radius: 50%;
          animation: load8 1.1s infinite linear;
        }
        @keyframes load8 {
          0% {
           transform: rotate(0deg);
          }
          100% {
           transform: rotate(360deg);
          }
        }
     </style>
     <script>
       function onLoad() {
         var loader = document.getElementById("cpay_loader");loader.className = "";}
     </script>
   </head>
   <body onload="onLoad();">
     more html here.....
   </body>
</html>
Joseph Tabajjwa
fuente
1

¿Qué hay de usar Pace?

Use esta dirección de enlace aquí.

https://github.hubspot.com/pace/docs/welcome/

1.En su sitio web, seleccione el estilo que desee y péguelo en index.css

2. ir a cdnjs Copie el enlace para Pace Js y agréguelo a sus etiquetas de script en public / index.html

3. Detecta automáticamente cargas web y muestra el ritmo en la parte superior del navegador.

También puede modificar la altura y la animación en el CSS también.

roqkabel
fuente
Impresionante y se puede integrar en poco tiempo.
UzumakiL