Vinnaren i pepparkakshustävlingen!
2018-01-26, 18:24
  #1
Medlem
Hallå Flashback,
Jag håller på att skriva ihop en funktion som "defer CSS". Jag vill gärna få lite feedback (ifall det är något jag inte tänker på, ifall det är dåligt skrivet, osv).

Är det, exempelvis, en "bra" använding av "for-loop" eller finns det något mot "document.body.scripts"?

Jag använder mig utav "readystatechange" för att kolla om DOM är redo med ett "if"-statement ifall 'target.readyState === "complete"'. Är det ett bra sätt för att kolla om DOM är färdigt eller är det bättre om jag använder mig av något annat?

Fick tyvärr inget svar på StackOverflow, så tänkte att jag provar min tur här.

Kod:
HTML-kod:
<script>
var deferCSS = function(tn, p) {
    // Fix for FOUC (Flash Of Unstyled Content)
    document.body.children[0].style.display = "none";

    // Start the defer
    var NST = document.querySelector('noscript'),
    ST      = document.querySelector(tn);
    if(tn == 'body script') {
      ST = document.scripts;
        for(var i = 0; i < ST.length; i++) {
          if(ST[i].parentNode.tagName == "BODY") {
            ST = ST[i];
            break;
          }
        }
    }

    // Add the event listener and start pasting the <link>s
    document.addEventListener("readystatechange", e => {

      var load = function() {
        ST.insertAdjacentHTML(p, NST.childNodes[0].data);
        document.body.children[0].style.display = "initial";
      }

      if(document.readyState === "complete") {
        window.setTimeout(load, 0);
        return;
      }

    });
}('body script', 'beforebegin');
</script>

Tack i förhand!
__________________
Senast redigerad av Fexell 2018-01-26 kl. 18:26.
Citera
2018-01-26, 18:37
  #2
Medlem
Vet inte exakt vad ditt script gör med varför inte använda jQuery?

Kod:
<body style="display:none;">
<script>
    $(document).ready(function() {
        $(body).show();
    });
</script>
</body>

(otestat)
Citera
2018-01-26, 19:06
  #3
Medlem
Citat:
Ursprungligen postat av blublang
Vet inte exakt vad ditt script gör med varför inte använda jQuery?

Kod:
<body style="display:none;">
<script>
    $(document).ready(function() {
        $(body).show();
    });
</script>
</body>

(otestat)

Försöker sätta mig in mer i JavaScript och för att jag vill inte behöva använda jQuery hela tiden. Vad scriptet gör är att ta allting innanför en <noscript> tag (där jag har alla <link> taggar till CSS), väntar på att DOM är färdigt för att lägga in <link> taggarna där man specificerat. Koden för att slippa FOUC är bara något jag testar just nu och försöker fixa. Har stött på lite problem där, dock. Jag undrar bara om det finns något bättre sätt att skriva min function på och om det är något jag skrivet fel och som sagt; kan förbättra.
Jag vet till exempel inte om "loop"-funktionen i min kod är nödvändig eller vilket som är det bästa sättet för att se om DOM färdigt (helst fullt renderat). Att använda jQuery för att "deferra" CSS är ju lite att motarbeta det som det ska göra.

Edit; Anledningen till denna snippet är pga. sådana sajter som erbjuder "Speed Test" för hemsidor, som till exempel Google gör, där man får ett felmeddelande om "Render blocking, defer CSS".
Citera
2018-01-26, 19:31
  #4
Medlem
Har du provat det här? https://stackoverflow.com/questions/...ously#40314216

Men är CSS ditt problem egentligen? Är det inte externa fonter som oftast är orsaken till att text är osynlig en kort stund i början?
Citera
2018-01-26, 20:17
  #5
Medlem
Citat:
Ursprungligen postat av blublang
Har du provat det här? https://stackoverflow.com/questions/...ously#40314216

Men är CSS ditt problem egentligen? Är det inte externa fonter som oftast är orsaken till att text är osynlig en kort stund i början?

Jag tror jag sett den lösningen. Problemet där är ju ifall JavaScript är avaktiverat, vilket kommer att leda till att ingen CSS laddas alls (med lösningen som skrivs i StackOverflow).

Jag hittade en kod från Google igår som gör det jag gör (i stort sett), bara att jag gör det till en funktion.

Google's kod:

HTML-kod:
    <noscript id="deferred-styles">
      <link rel="stylesheet" type="text/css" href="small.css"/>
    </noscript>
    <script>
      var loadDeferredStyles = function() {
        var addStylesNode = document.getElementById("deferred-styles");
        var replacement = document.createElement("div");
        replacement.innerHTML = addStylesNode.textContent;
        document.body.appendChild(replacement)
        addStylesNode.parentElement.removeChild(addStylesNode);
      };
      var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
          window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
      if (raf) raf(function() { window.setTimeout(loadDeferredStyles, 0); });
      else window.addEventListener('load', loadDeferredStyles);

Men nu är det inte riktigt att jag frågar "om man ska göra det/om det är rekommenderat", utan jag undrar mer om min kod är bra. Är det något jag, exempelvis, missar, eller dylikt.

Exempel:
Är det en bra lösning med min "for-loop"? Finns det något som skulle vara bättre än en "for-loop"? Är "document.addEventListener('readystatechange') " en bra lösning till att se ifall DOM helt laddat?
Citera
2018-01-26, 20:22
  #6
Medlem
En fråga som kommer upp i mitt huvud när jag tittar på Google's lösning är vad betyder det när man gör såhär:

HTML-kod:
if (raf) raf(function() { window.setTimeout(loadDeferredStyles, 0); });

Vad menas med att öppna funktionen med "raf": "raf(function()..."? Vad gör "raf" i den situationen?

Edit; Är det att "var raf" omdefinieras till funktionen?
Citera
2018-01-26, 21:42
  #7
Medlem
Povels avatar
Citat:
Ursprungligen postat av Fexell
Hallå Flashback,
...
Är det, exempelvis, en "bra" använding av "for-loop" eller finns det något mot "document.body.scripts"?
...
Kod:
var deferCSS = function(tnp) {
    ...
    
ST      document.querySelector(tn);
    if(
tn == 'body script') {
      
ST document.scripts;
        for(var 
0ST.lengthi++) {
          if(
ST[i].parentNode.tagName == "BODY") {
            
ST ST[i];
            break;
          }
        }
    }
    ...
}(
'body script''beforebegin'); 

Tack i förhand!

Varför letar du upp "ST" på det där sättet? Det tycks som att du är ute efter det första <script> som ligger som direkt barn till <body>. Du kan ju då skicka in selektorn "body > script" istället så slipper du hela if-satsen och allt loopande där.

Och varför letar du ens upp just den scripttaggen med en selektor (eller i värsta fall loop)? Det den sen tycks tjäna till är att vara måltavla för adjacentHTML-ingreppet. Detta behöver ju 1) inte ske just direkt i <body> och 2) om du ändå vill det kan du ju ha din "deferCSS"-kod i en scripttagg direkt i body nånstans och få en referens direkt till den med document.currentScript.

Själv skulle jag nog ta CSS-länkarna från noscript, slänga in i en <span> och bara appenda denna span till body.. harmlöst.

Kod:
const addStyleSheets = () => {
  const 
sheetsHTML NST.textContent,
    
stylesWrap document.createElement("span");
  
stylesWrap.innerHTML sheetsHTML;
  
document.body.appendChild(stylesWrap);
};

document.addEventListener("readystatechange"=> {
  if (
"complete" == document.readyState) {
    
addStyleSheets();
  }
}); 

Dock skulle jag aldrig välja att generellt rota upp styles från inuti <noscript> (min site utan js skulle troligen ha sina egna stylesheets, och de riktiga kan jag ju injecta med javascript på slutet).
Min känsla är att det som står i noscript skall gälla (endast) i noscript.

/p
__________________
Senast redigerad av Povel 2018-01-26 kl. 21:47.
Citera
2018-01-26, 22:39
  #8
Medlem
Citat:
Ursprungligen postat av Povel
Varför letar du upp "ST" på det där sättet? Det tycks som att du är ute efter det första <script> som ligger som direkt barn till <body>. Du kan ju då skicka in selektorn "body > script" istället så slipper du hela if-satsen och allt loopande där.

Och varför letar du ens upp just den scripttaggen med en selektor (eller i värsta fall loop)? Det den sen tycks tjäna till är att vara måltavla för adjacentHTML-ingreppet. Detta behöver ju 1) inte ske just direkt i <body> och 2) om du ändå vill det kan du ju ha din "deferCSS"-kod i en scripttagg direkt i body nånstans och få en referens direkt till den med document.currentScript.

Själv skulle jag nog ta CSS-länkarna från noscript, slänga in i en <span> och bara appenda denna span till body.. harmlöst.

Kod:
const addStyleSheets = () => {
  const 
sheetsHTML NST.textContent,
    
stylesWrap document.createElement("span");
  
stylesWrap.innerHTML sheetsHTML;
  
document.body.appendChild(stylesWrap);
};

document.addEventListener("readystatechange"=> {
  if (
"complete" == document.readyState) {
    
addStyleSheets();
  }
}); 

Dock skulle jag aldrig välja att generellt rota upp styles från inuti <noscript> (min site utan js skulle troligen ha sina egna stylesheets, och de riktiga kan jag ju injecta med javascript på slutet).
Min känsla är att det som står i noscript skall gälla (endast) i noscript.

/p

Tack för din feedback. Visste inte att man kan köra "querySelector('body script');". Satt o störde mig på att jag skrev en loop för något som borde, och tydligen är, så enkelt.

Vad är det som är fördelen med scriptet som du skrev gentemot min? Är det prestandan eller något annat?

Skulle du använda något annat än "readystatechange" (typ, "load")?
Citera

Stöd Flashback

Flashback finansieras genom donationer från våra medlemmar och besökare. Det är med hjälp av dig vi kan fortsätta erbjuda en fri samhällsdebatt. Tack för ditt stöd!

Stöd Flashback