Jump to content

[TUT] Toggelable divisions


David22
 Share

Recommended Posts

Tutorial



Toggable division met HTML, CSS en jQuery

Inleiding

Op dit forum hebben wij meerdere categorieën voor de verschillende fora, en op de homepage zijn deze in en uitklapbaar. In deze tutorial zal ik je laten zien hoe je zoiets voor je eigen website kan maken.

Wat gaan we doen?

In deze tutorial zal ik laten zien hoe je met een lage hoeveelheid code meerdere in- en uitklapbare div's kan maken. Deze code is schaalbaar naar een ontelbaar eindig divisions. Hier een voorbeeld van wat we gaan maken:

6R2On7U.png

Ik ga er van uit dat enige basiskennis van HTML, CSS en jQuery al aanwezig is.

De bestanden

Voor deze tutorial gebruik in de volgende bestanden:

  • index.html
  • stylesheet.css
  • expand.png
  • minimize.png

Alle gebruikte bestanden zullen weer onderaan deze tutorial te downloaden zijn.

De code

Tijd voor het echte werk! Voordat ik begin met code te plaatsen, zal ik eerst een stappenplan maken:

  1. Maak de HTML code
  2. Geef deze uitstraling met CSS
  3. Maak de interactie compleet met jQuery
  4. Houd rekening met Javscript-loze mensen

De HTML

Om de basis-HTML code te genereren, maak ik altijd gebruik van htmlshell.com. Hierop kan je heel makkelijk aanvinken welke elementen je in je HTML code wil, waarom zou je het wiel opnieuw uitvinden? Met behulp van deze tool heb ik de volgende skeleton gegenereerd:

<!DOCTYPE html>
<html>
   <head>
         <meta charset="UTF-8">
         <title>title</title>
         <link rel="stylesheet" href="stylesheet.css" type="text/css">
    </head>
    <body>

         <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" type="text/javascript"></script>
    </body>
</html>

Iedere toggable division in deze pagina zal een header (waar in de afbeelding "Menu X" staat) en een content (waar in het voorbeeld "Lorum Ipsum..." staat) bevatten. Om later met jQuery onderscheid tussen de verschillende divisions te kunnen maken, plaats ik deze binnen een container-div:

<div class="container">
   <div class="header">
       <h1>Menu 1</h1>
   </div>

   <div class="content">
       Lorem ipsum...
   </div>
</div>

Ook moet de afbeelding minimize.png, de knop welke zal dienen als in- en uitklapknop, nog in de header geplaatst worden:

<div class="header">
   <h1>Menu 1</h1>
   <img class="toggle" src="minimize.png" alt="Toggle" />
</div>

Ons resultaat tot nu toe ziet er als volgt uit:

tXOeH0V.png

Heel leuk, maar het lijkt nergens op. Gelukkig komt CSS om de hoek kijken!

De CSS

We beginnen met de styling van de header-div:

div.header { }

Ik maak deze 500x30 pixels groot, en ik geef 'm een zwarte rand van 1 pixel:

width:500px;
height:30px;
border:1px solid #000;

Vervolgens gaan we er voor zorgen dat de minimize-afbeelding mooi rechts komt te staan. Deze zal ik absoluut gaan plaatsen. Omdat ik dat wil gaan doen, moet ik bij div.header het volgende regeltje nog toevoegen:

position:relative;

Dit zorgt ervoor dat de afbeelding absoluut ten opzichte van div.header geplaatst zal worden, in plaats van absoluut ten opzichte van de body.

Nu is het tijd om daadwerkelijk CSS voor de afbeelding te gaan schrijven:

div.header img.toggle { }

Zoals ik al zei gaan we deze absoluut plaatsen:

position:absolute;

Ik wil deze met een margin van 5 pixels in de rechterbovenhoek plaatsen (5px van boven & 5px van rechts):

top:5px;
right:5px;

Vervolgens wil ik 'm verticaal in het midden hebben. De hoogte van div.header is 30 pixels, dus om van onderen ook 5px ruimte te hebben moet de afbeelding 30 - 5 - 5 = 20 pixels hoog zijn:

height:20px;

De laatste stap om de afbeelding te stijlen is de gebruiker het idee geven dat het een knop is, door de muisaanwijzer in een "klikhandje" te veranderen als deze boven de afbeelding hangt:

cursor:pointer;

De content-div geeft ik de goede breedte mee, en ik zet er nog een mooie lijn omheen. De lijn hoeft alleen boveaan de div niet te bestaan, want hier zit div.header al:

div.content {
 width:500px;
 border:1px solid #000;
 border-top:none;
}

Om de h1 nog mooi te stijlen pak ik een mooi font uit de database van Google Fonts, waarvan ik meegegeven waarden als de margin en padding nog even reset:

h1 {
 font-family: 'Alef', sans-serif;
 margin:0;
 padding:0;
 font-size:18px;
}

Bijkomende code van Google Fonts is het volgende in de head van de HTML:

<link href='http://fonts.googleapis.com/css?family=Alef' rel='stylesheet' type='text/css'>

Dit mag onder de link naar het stylesheet geplaatst worden. Verder wil ik de h1 nog netjes een stukje ingeschoven in de header, waardoor ik een margin toevoegd aan de header. Ook wil ik de text verticaal gecentreerd:

line-height:30px;
padding-left:15px;

Omdat ik een padding van 15px toevoeg, wordt de header 15 pixels breder. Dit moet ik dus ook voor div.content doen, om ze even lang te laten blijven:

width:515px;

Dit geeft ons tot nu toe de volgende HTML en CSS:

HTML:

<!DOCTYPE html>
<html>
   <head>
       <meta charset="UTF-8">
       <title>Division toggle</title>
       <meta name="author" content="David22">
       <link rel="stylesheet" href="stylesheet.css" type="text/css">
       <link href='http://fonts.googleapis.com/css?family=Alef' rel='stylesheet' type='text/css'>
   </head>
   <body>
     <div class="container">
       <div class="header">
         <h1>Menu 1</h1>
         <img class="toggle" src="minimize.png" alt="Toggle" />
       </div>

       <div class="content">
         Lorem ipsum...
       </div>
     </div>
     <div class="container">
       <div class="header">
         <h1>Menu 2</h1>
         <img class="toggle" src="minimize.png" alt="Toggle" />
       </div>
       <div class="content">
         Lorem ipsum...
       </div>
     </div>
     <div class="container">
       <div class="header">
         <h1>Menu 3</h1>
         <img class="toggle" src="minimize.png" alt="Toggle" />
       </div>
       <div class="content">
         Lorem ipsum...
       </div>
     </div>
       <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" type="text/javascript"></script>
   </body>
</html>

CSS:

div.container {
 margin-bottom:10px;
}

div.header {
 width:500px;
 height:30px;
 border:1px solid #000;
 position:relative;
 line-height:30px;
 padding-left:15px;
} 

div.header img.toggle {
 position:absolute;
 top:5px;
 right:5px;
 height:20px;
 cursor:pointer;
}

div.content {
 width:515px;
 border:1px solid #000;
 border-top:none;
}

h1 {
 font-family: 'Alef', sans-serif;
 margin:0;
 padding:0;
 font-size:18px;
}

Okee, nu ziet alles er goed uit. Tijd om de functionaliteit toe te voegen!

De jQuery

We gaan aan de slag met jQuery als de volledige HTML geladen is. Plaats daarom deze code in je HTML:

<script>
$(document).ready(function() {
 // Code here
});
</script>

Het script moet geplaatst worden onder:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" type="text/javascript"></script>

Vervolgens wachten we tot er op img.toggle geklikt wordt. Dit doen we op de volgende manier:

$("img.toggle").click(function() {
 // code here
});

Vervolgens kunnen we de juiste div.content in- danwel uitschuiven met slideToggle(), een functie van jQuery welke dit voor ons doet. Maar hoe komen we bij de juiste div.content? Dit is per slot van rekening een class, met (in ons voorbeeld 3) meerdere instanties! Hiervoor gaan we een reisje door de DOM maken, beginnend bij $(this), de afbeelding.

Vanaf de afbeelding reizen we met parent() naar de "ouder" van de afbeelding, het element wat een niveau hoger in de DOM staat -- in ons geval div.header. Deze div.header heeft een "broer" van de klasse div.content, welke precies die ene div is welke we willen in- of uitklappen. Deze vragen we op met siblings("div.content"). Doordat dit de enige div.content is welke een directe sibling is van div.header (de rest staat in een andere div.container), zal er maar een in- of uitschuiven. De uiteindelijke code om de goede div dan aan te passen is:

$(this).parent().siblings("div.content").slideToggle();

Dat werkt! Maar zou het niet leuk zijn als na het inklappen, de - in een + zou veranderen? Hiervoor voegen we een functie toe welke uitgevoerd wordt als het in- of uitklappen voltooid is:

$(this).parent().siblings("div.content").slideToggle(function() {
 // code here
});

Binnen deze functie kunnen we de huidige url van de afbeelding, minimize.png of expand.png, opvragen. Het enige probleem is dat $(this) nu verwijst naar div.content inplaats van img.toggle! Daarom moeten we de link naar de afbeelding opslaan voordat we de slideToggle uit gaan voeren:

// hier is $(this) de afbeelding
var imgObj = $(this);
$(this).parent().siblings("div.content").slideToggle(function() {
 // hier is $(this) de div.content, maar imgObj nog de afbeelding!
});

Vervolgens gaan we de url van de afbeelding opvragen, en kijken of deze op minimize.png of expand.png eindigd:

src = imgObj.prop("src");
if(/minimize.png$/i.test(src)) {
 // is -, moet + worden
}
else {
 // is geen -, dus moet - worden
}

Om de eigenschappen van een object te veranderen, heeft jQuery (onder andere) de volgende functie:

imgObj.prop("src", "expand.png");

Bovenstaande code veranderd het src property van imgObj in expand.png -- precies wat we willen!

if(/minimize.png$/i.test(src)) {
 imgObj.prop("src", "expand.png");
}
else {
 imgObj.prop("src", "minimize.png");
}

Onze code werkt nu! De jQuery ziet er als volgt uit:

<script>
$(document).ready(function() {
 $("img.toggle").click(function() {
   var imgObj = $(this);
   $(this).parent().siblings("div.content").slideToggle(function() {
     src = imgObj.prop("src");
     if(/minimize.png$/i.test(src)) {
       imgObj.prop("src", "expand.png");
     }
     else {
       imgObj.prop("src", "minimize.png");
     }
   });
 });
});
</script>

Er is echter nog een stap...

Een wereld zonder Javascript

Javascript, en dus ook jQuery, wordt client-side (op de computer van de gebruiker) uitgevoerd. Hierdoor kan support hiervoor niet altijd aanwezig zijn. Daarom moeten we rekening houden met mensen welke geen gebruik maken van Javascript. In ons geval is dat heel eenvoudig te doen door de toggle-knop te verbergen, en deze in te schakelen als de gebruiker Javascript aan heeft staan. De knop uitschakelen doen we door het volgende aan de img.toggle-CSS toe te voegen:

display:none;

Inschakelen doen we eenvoudig door het CSS-attribuut met jQuery aan te passen:

$("img.toggle").css("display", "block");

Afsluiting

En klaar! Ik hoop dat je wat aan deze tutorial hebt gehad, laat gerust een berichtje achter :)

Volledige code en bestanden zijn op http://www.solidfiles.com/d/22424826a4/ te downloaden. Script is in werking te zien op http://jsfiddle.net/KUXTB/4/

Edited by David22
Link to comment
Share on other sites

Waarom ga je een reguliere expressie/regex uitvoeren (die overigens ook een bestand als expandopng, expand?png of wat dan ook matcht) op een plaatje, als je ook heel makkelijk kunt kijken of de toggle een bepaalde klasse bevat in de HTML (wat iets lichter is)? Zo heb ik mijn eigen toggles (inclusief cookies en ander spul) gemaakt.. Dan kun je pas binnen de stylesheet de invulling van je plaatje geven (zodat je script ook simpel te porten is, zonder al te veel HTML).

Link to comment
Share on other sites

Waarom ga je een reguliere expressie/regex uitvoeren (die overigens ook een bestand als expandopng, expand?png of wat dan ook matcht) op een plaatje, als je ook heel makkelijk kunt kijken of de toggle een bepaalde klasse bevat in de HTML (wat iets lichter is)? Zo heb ik mijn eigen toggles (inclusief cookies en ander spul) gemaakt.. Dan kun je pas binnen de stylesheet de invulling van je plaatje geven (zodat je script ook simpel te porten is, zonder al te veel HTML).

Dat is uiteraard ook een mogelijkheid, nog best wel een nette oplossing ook. Ik zal de tutorial binnenkort uitbreiden met deze mogelijkheid, maar er leiden natuurlijk meerdere wegen naar Rome!

Link to comment
Share on other sites

Ik raad je in ieder geval even aan het puntje in je regex te vervangen (of liever gezegd, te escapen). Dit is niet zozeer een probleem binnen dit script, maar mocht je vaker met regexs gaan werken, zul je merken dat het niet altijd de gewenste resultaten geeft: een puntje matcht namelijk alles :puh:

Ik kijk in ieder geval uit naar je volgende release!

Link to comment
Share on other sites

Ik raad je in ieder geval even aan het puntje in je regex te vervangen (of liever gezegd, te escapen). Dit is niet zozeer een probleem binnen dit script, maar mocht je vaker met regexs gaan werken, zul je merken dat het niet altijd de gewenste resultaten geeft: een puntje matcht namelijk alles :puh:

Ik kijk in ieder geval uit naar je volgende release!

Ahja, dat is waar ook :puh: Regexs blijven een zwak punt van mij... Misschien iets om eens aan te gaan werken. :puh:

Link to comment
Share on other sites

Ik raad je in ieder geval even aan het puntje in je regex te vervangen (of liever gezegd, te escapen). Dit is niet zozeer een probleem binnen dit script, maar mocht je vaker met regexs gaan werken, zul je merken dat het niet altijd de gewenste resultaten geeft: een puntje matcht namelijk alles puh2.gif

Ik kijk in ieder geval uit naar je volgende release!

*Bijna alles

geen newlines :puh:

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...