Spotlight Constrained Stickies met jQuery

Om de week houden we een ultragerichte kijk op een interessant en nuttig effect, plug-in, hack, bibliotheek of zelfs een handige technologie. We proberen dan de code te deconstrueren of er een leuk klein project mee te maken.

Vandaag gaan we een plug-in bekijken die een vrij netjes effect bewerkstelligt - het is vrij moeilijk om het in een zin uit te leggen, dus je kunt net zo goed op de knop Doorgaan klikken om te beginnen na de sprong.


Een woord van de auteur

Als webontwikkelaars hebben we toegang tot een duizelingwekkende hoeveelheid kant-en-klare code, of het nu een klein fragment is of een volledig ontwikkeld raamwerk. Tenzij je iets ongelooflijk speciaals doet, is de kans groot dat er al iets vooraf is voorbereid dat je kunt gebruiken. Jammer genoeg kwijnen veel van deze geweldige aanbiedingen in anonimiteit, speciaal voor de niet-hardcore menigte.

Deze serie probeert dit probleem op te lossen door het introduceren van een aantal echt goed geschreven, nuttige code - zij het een plug-in, een effect of een technologie voor de lezer. Verder, als het klein genoeg is, zullen we proberen de code te deconstrueren en begrijpen hoe het voodoo doet. Als het veel groter is, zullen we proberen om er een miniproject mee te maken om de touwen te leren en hopelijk te begrijpen hoe we het in de echte wereld kunnen gebruiken.


Introductie van stickyFloat

Hier is wat snelle info:

  • Type: Inpluggen
  • Technologie: JavaScript [Gebouwd op de jQuery-bibliotheek]
  • Functie: Zwevende inhoud alleen binnen de beperkingen van de grenzen van de ouder
  • Plugin-startpagina: Hier

Het probleem

In veel gevallen moet u de inhoud laten zweven terwijl u bladert, maar alleen binnen zijn ouder.

Zwevende inhoud terwijl een gebruiker door de rest van de pagina scrolt, is kinderspel. JavaScript is niet nodig - u kunt het gewoon doen met oude CSS. Klap een positie: vast verklaring erover en boom !, je hebt een container die op een specifieke locatie op de pagina is gerepareerd - het zweeft in de pagina om meer informeel te zijn.

Maar laten we eerlijk zijn, het werkt niet bij elke lay-out. Je zou een beetje vooruit kunnen plannen en het op de pagina kunnen plaatsen, zodat het nooit zou interfereren met belangrijke elementen, maar het zou noch volledig onfeilbaar noch herbruikbaar zijn elders zonder uitgebreide veranderingen.

In deze gevallen moet de inhoud zwevend zijn terwijl u bladert, maar alleen binnen zijn ouder.. Als je je afvraagt, ja, deze functionaliteit is een variant van degene die Andrew je liet zien in de tutorial van vorige week, en dat is hoe ik deze plug-in te weten kwam.

Zoals je zult vinden in webontwikkeling, net zoals multivariabele calculus, zijn er vaak een aantal oplossingen voor een bepaald probleem. Laten we naar een van die alternatieve oplossingen kijken.


Het deconstrueren van de logica

De algemene logica of workflow van de plug is eigenlijk vrij eenvoudig. Ik zal het je laten zien. Houd in gedachten dat ik naar het element zal verwijzen dat moet worden bestuurd kleverig van nu af aan.

Maar voordat we beginnen, is hier een snelle mock-up om de hiërarchie te tonen:

De volledige logica van de plug-in kan worden afgezwakt tot:

  • Bereken de huidige positie van de plakkerige elementen ouder, ten opzichte van het document. Gemarkeerd als 1 in de afbeelding.
  • Verkrijgen van de hoogte van de ouder ook - Zodat we weten wanneer we moeten stoppen met zweven als we voorbij de ouder zijn. Gemarkeerd als 2.
  • Bereken hoever de pagina is gescrold - Om erachter te komen of we naar de ouder kijken - om te zien of we binnen bereik zijn. In de bovenstaande afbeelding markeert de horizontale lijn de hypothetische bovenkant van de huidige viewport. In dit geval is deze waarde de afstand tussen de punten gemarkeerd als 3.
  • Met behulp van de twee waarden die we hierboven hebben berekend, kunnen we heel snel achterhalen of de plakkerig gepositioneerd moet worden.

Als je in de war bent, wees dat dan niet. Laten we bijvoorbeeld een aantal voorbeeldnummers bekijken:

  • De ouder van de sticky is aanwezig 10px vanaf de bovenkant van de pagina.
  • De ouder is 100px hoog.
  • De pagina is gescrold 50px in één scenario en 150px in de andere.

Dus op basis van bovenstaande informatie kun je dat afleiden

In scenario één - de plakker moet op de juiste manier opnieuw worden geduwd. Waarom? De pagina is 10x gescrolld vanaf de top - 10 komt van de pagina zelf, terwijl de rest van de ouder van de sticky komt. De ouder is dus zichtbaar in het hoofdvenster.

In scenario twee - de plakker kan alleen worden gelaten. Van de 150 pixels komt 10 van de pagina, 100 van het bovenliggende element en de rest wordt overgenomen door de rest van het pagina-element. Dit houdt in dat de gebruiker voorbij de ouder is gescrold en dat we niets hoeven te doen.

Als je op dit moment nog steeds wazig bent, maak je geen zorgen. Ik zal een beetje meer uitleggen tijdens het wandelen door de bron.


De bron deconstrueren

De bron ontdaan van opmerkingen is slechts een smidgen van meer dan 30 regels lang. Zoals altijd zullen we de code doorlopen en uitleggen wat elke regel doet.

Hier is de bron, ter referentie.

 $ .fn.stickyfloat = function (options, lockBottom) var $ obj = this; var parentPaddingTop = parseInt ($ obj.parent (). css ('padding-top')); var startOffset = $ obj.parent (). offset (). top; var opts = $ .extend (startOffset: startOffset, offsetY: parentPaddingTop, duration: 200, lockBottom: true, options); $ obj.css (position: 'absolute'); if (opts.lockBottom) var bottomPos = $ obj.parent (). height () - $ obj.height () + parentPaddingTop; if (bottomPos < 0 ) bottomPos = 0;  $(window).scroll(function ()  $obj.stop(); var pastStartOffset = $(document).scrollTop() > opts.startOffset; var objFartherThanTopPos = $ obj.offset (). top> startOffset; var objBiggerThanWindow = $ obj.outerHeight () < $(window).height(); if( (pastStartOffset || objFartherThanTopPos) && objBiggerThanWindow ) var newpos = ($(document).scrollTop() -startOffset + opts.offsetY ); if ( newpos > bottomPos) newpos = bottomPos; if ($ (document) .scrollTop () < opts.startOffset ) newpos = parentPaddingTop; $obj.animate( top: newpos , opts.duration );  ); ;

Tijd om te zien wat het eigenlijk doet. Ik ga ervan uit, je hebt een redelijk basiskenmerk van JavaScript.

 $ .fn.stickyfloat = function (options, lockBottom) ;

Stap 1 - De generieke wrapper voor een jQuery-plug-in. Zoals je waarschijnlijk weet, opties is een object dat verschillende opties bevat om het gedrag van de plug-in te configureren. lockBottom, Interessant, geeft aan of de gewenste functionaliteit is ingeschakeld of niet. We laten het maar aan.

 var $ obj = this;

Stap 2 - Houd een verwijzing naar het doorgegeven element bij. In deze context, deze verwijst naar het DOM-element dat overeenkomt met de selector die je hebt doorgegeven. Bijvoorbeeld als je bent geslaagd #menu, deze wijst naar het element met die ID.

 var parentPaddingTop = parseInt ($ obj.parent (). css ('padding-top'));

Stap 3 - Dit is alleen om het effect glad te strijken als het bovenliggende element een grote opvulling heeft. Als dit het geval is, bevat dit de opvulling in de berekening.

 var startOffset = $ obj.parent (). offset (). top;

Stap 4 - We berekenen de positie van de ouder ten opzichte van het document met behulp van de compenseren jQuery-methode. We werken via de DOM met behulp van de ouder methode. Wij $ obj omdat we het plakkerige al hebben gecached. Druk op de jQuery API-documentatie als u niet bekend bent met deze methoden.

In dit geval is de afstand vanaf de bovenkant voldoende, zodat we die waarde alleen krijgen.

 var opts = $ .extend (startOffset: startOffset, offsetY: parentPaddingTop, duration: 200, lockBottom: true, options);

Stap 5 - Een vrij algemeen onderdeel van het ontwikkelproces voor jQuery-plug-ins. We voegen in essentie de doorgegeven opties samen met een aantal presets samen om een ​​laatste reeks opties te krijgen die in de hele code wordt gebruikt. Houd er rekening mee dat de doorgegeven parameters altijd voorrang hebben op de standaardwaarden.

 $ obj.css (position: 'absolute');

Stap 6 - Het betreffende effect wordt gecreëerd door het manipuleren van de elementen top CSS-waarde, dus we gaan gewoon door en stellen de positie in op absoluut als deze nog niet zo is ingesteld.

 if (opts.lockBottom) var bottomPos = $ obj.parent (). height () - $ obj.height () + parentPaddingTop; if (bottomPos < 0 ) bottomPos = 0; 

Stap 7 - Zoals hierboven vermeld, de lockBottom optie geeft aan of het effect in kwestie werkt of niet. Indien ingeschakeld, kunnen we beginnen met het berekenen. Wat we berekenen, is het afkappunt waarboven we het kleverige niet hoeven te verplaatsen.

Natuurlijk kun je gaan door gewoon de hoogte van de ouder te berekenen, maar het effect zal ongeraffineerd zijn. Je moet rekening houden met de hoogte van de plakker zelf langs eventuele paddings op de ouder zelf.

 $ (venster) .scroll (function () // veel code)

Stap 8 - We haken onze code, binnen een anonieme functie, aan de ramen ' rol evenement. Toegegeven, dit is niet de meest efficiënte manier om verder te gaan, maar we zullen het voorlopig negeren.

 $ Obj.stop ();

Stap 9 - De eerste volgorde van zeggen is om alle lopende animaties op het plakkerige element te stoppen. De hou op methode zorgt hier voor.

 var pastStartOffset = $ (document) .scrollTop ()> opts.startOffset; var objFartherThanTopPos = $ obj.offset (). top> startOffset; var objBiggerThanWindow = $ obj.outerHeight () < $(window).height();

Stap 10 - Deze drie variabelen bevatten waarden die we een beetje later zullen gebruiken.

  • pastStartOffset controleert of we voorbij de bovengrens van het bovenliggende element zijn gescrold. Vergeet niet dat we de compenseren methode om de ruimte tussen het bovenliggende element en het document te achterhalen. We weten hoe ver je bent gescrold met behulp van de scrollTop methode. Dit is de afstand tussen de bovenkant van het document en de bovenkant van de huidige viewport.
  • objFartherThanTopPos controleert of de sticky zich in de standaardpositie bevindt - op de bovenzijde van de bovenliggende. Als we voorbij de top van de ouder, we willen niet dat het buiten zweeft.
  • objBiggerThanWindow controleert of de totale hoogte van de plakkerig is dan de grootte van het venster. Als dat het geval is, heeft het geen zin om het plakkerige element te manipuleren.
 if ((pastStartOffset || objFartherThanTopPos) && objBiggerThanWindow) // Meer code

Stap 11 - Dit is waar de plug-in berekent of we het kleverige element moeten manipuleren. Wat de bovenstaande regel doet:

  • Controleer of de gebruiker scrolt precies in het bereik van het bovenliggende element. We controleren of de gebruiker zich onder de bovengrens van de ouder bevindt of dat de sticky bovenaan staat.
  • Zoals hierboven vermeld, gaan we alleen verder als de plakker kleiner is dan de venstergrootte.

We gaan alleen verder als beide van deze voorwaarden zijn voldaan.

 var newpos = ($ (document) .scrollTop () -startOffset + opts.offsetY);

Stap 12 - Deze regel definieert een variabele, newpos, die de positie specificeert waarnaar het sticky-element moet worden geanimeerd. Zoals je misschien hebt gemerkt, is de berekening redelijk eenvoudig als je de bovenstaande afbeelding in gedachten houdt. Ontdek de gescrolde afstand, voeg de bovenvulling van de bovenliggende laag toe en tenslotte de afstand tussen het document en de ouder af - het startpunt. Dit geeft je de afstand, in pixels, tussen de bovenkant van het bovenliggende element tot het punt binnenin, waar het plakkerige moet worden geplaatst.

 if (newpos> bottomPos) newpos = bottomPos;

Stap 13 - Als we voorbij de ondergrens van het bovenliggende element hebben gescrolld, is het niet nodig om dingen verder te manipuleren. Vergrendel daar zijn positie.

 if ($ (document) .scrollTop () < opts.startOffset ) newpos = parentPaddingTop;

Stap 14 - Als we boven de bovengrens van de ouder hebben gescrold, houd je deze daar vergrendeld zodat deze niet verder omhoog komt.

 $ obj.animate (top: newpos, opts.duration);

Stap 15 - Helemaal klaar! We animeren eenvoudigweg het kleverige element dat de vereiste doorgeeft top waarde samen met de duur van het effect met behulp van de bezielen jQuery-methode.


Gebruik

Zoals je waarschijnlijk op dit punt al hebt afgeleid, is het gebruik als volgt:

 $ ('# menu'). stickyfloat (duration: 500);>

In plaats van het voorbeeld mini-project uit te leggen, zoals de vorige keer, heb ik in plaats daarvan besloten om het alleen maar te bouwen en je de code te geven.

Hier zijn de relevante delen van de demo, de rest is boilerplate:

De HTML

 
Kleverig menu
Ik wilde hier iets ongelooflijks, ongegeneerd geestigs schrijven. Ik faalde. :(
Ja, ik volg je overal zolang je binnen mijn ouder bent
Je verwachtte hier iets slims, is het niet? Ik weet dat je het deed! Fess up!

De CSS

 .sectie opvulling: 10px; width: 900px; marge: 0 auto; background-color: # f1f1f1; position: relative;  .sectie .content height: 800px; background-color: #ddd; margin-left: 250px; text-align: center; color: # 333; font-size: 16px;  .sectie .menu positie: absoluut; left: 10px; width: 240px; Hoogte: 100px; achtergrond: # 06C; text-align: center; color: # fff; font-size: 14px; 

JavaScript

 $ ('# menu'). stickyfloat (duration: 400); $ ('# menu2'). stickyfloat (duration: 400);

Als je de bestanden doorleest terwijl je dit artikel leest, zou het redelijk zelfverklarend moeten zijn, maar je bent meer dan welkom om me te slaan met vragen als een onderdeel onduidelijk is.


Afsluiten

En we zijn klaar. We hebben een ongelooflijk nuttige plug-in bekeken, de broncode doorlopen en uiteindelijk klaar met het maken van een miniproject.

Vragen? Leuke dingen om te zeggen? Kritiek? Klik op het gedeelte Opmerkingen en laat een opmerking achter. Heel erg bedankt voor het lezen!