--- title: Exemples pratiques de positionnement slug: Learn/CSS/CSS_layout/Practical_positioning_examples translation_of: Learn/CSS/CSS_layout/Practical_positioning_examples original_slug: Apprendre/CSS/CSS_layout/Exemples_pratiques_de_positionnement ---
Cet article montre comment construire quelques exemples réels de choses que vous pouvez faire avec le positionnement.
Prérequis: | Les bases du HTML (étudier Introduction au HTML), et une idée du fonctionnement du CSS (étudier Introduction au CSS.) |
---|---|
Objectif: | Avoir une idée des aspects pratiques du positionnement |
Le premier exemple que nous allons examiner est une boîte d'information à onglets classique - une fonction très courante utilisée lorsque vous voulez regrouper beaucoup d'informations dans une petite zone. Cela inclut les applications gourmandes en informations comme les jeux de stratégie/guerre, les versions mobiles de sites Web où l'écran est étroit et l'espace limité, et les boîtes d'information compactes où vous pourriez vouloir rendre beaucoup d'informations disponibles sans qu'elles remplissent toute l'interface utilisateur. Notre exemple simple ressemblera à ceci une fois que nous aurons terminé :
Note: You can see the finished example running live at info-box.html (source code). Check it out to get an idea of what you will be building in this section of the article.
Vous pourriez vous dire "pourquoi ne pas créer des onglets séparés sous forme de pages web séparées, et faire en sorte que les onglets permettent de cliquer sur les pages séparées pour créer l'effet ?" Ce code serait plus simple, oui, mais alors chaque "page" séparée serait en fait une nouvelle page web, ce qui rendrait plus difficile la sauvegarde des informations entre les vues, et intégrerait cette fonctionnalité dans un design d'interface plus large. De plus, les applications dites " à page unique " deviennent très populaires - en particulier pour les interfaces Web mobiles - parce que le fait que tout soit servi dans un seul fichier réduit le nombre de requêtes HTTP nécessaires pour voir tout le contenu, ce qui améliore les performances.
Note: Some web developers take things even further, only having one page of information loaded at once, and dynamically changing the information shown using a JavaScript feature such as XMLHttpRequest. At this point in your learning however we want to keep things as simple as possible. There is some JavaScript later on, but only a tiny bit.
Pour commencer, nous aimerions que vous fassiez une copie locale du fichier HTML de départ — info-box-start.html. Enregistrez ce fichier dans un endroit approprié sur votre ordinateur et ouvrez-le dans votre éditeur de texte. Examinons le HTML contenu dans le body:
<section class="info-box"> <ul> <li><a href="#" class="active">Tab 1</a></li> <li><a href="#">Tab 2</a></li> <li><a href="#">Tab 3</a></li> </ul> <div class="panels"> <article class="active-panel"> <h2>The first tab</h2> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque turpis nibh, porttitor nec venenatis eu, pulvinar in augue. Vestibulum et orci scelerisque, vulputate tellus quis, lobortis dui. Vivamus varius libero at ipsum mattis efficitur ut nec nisl. Nullam eget tincidunt metus. Donec ultrices, urna maximus consequat aliquet, dui neque eleifend lorem, a auctor libero turpis at sem. Aliquam ut porttitor urna. Nulla facilisi.</p> </article> <article> <h2>The second tab</h2> <p>This tab hasn't got any Lorem Ipsum in it. But the content isn't very exciting all the same.</p> </article> <article> <h2>The third tab</h2> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque turpis nibh, porttitor nec venenatis eu, pulvinar in augue. And now an ordered list: how exciting!</p> <ol> <li>dui neque eleifend lorem, a auctor libero turpis at sem.</li> <li>Aliquam ut porttitor urna.</li> <li>Nulla facilisi</li> </ol> </article> </div> </section>
Nous avons un élément {{htmlelement("section")}} avec une class
info-box
, qui contient une {{htmlelement("ul")}} et une {{htmlelement("div")}}. La liste non ordonnée contient trois éléments de liste avec des liens à l'intérieur, qui deviendront les véritables onglets sur lesquels il faudra cliquer pour afficher nos panneaux de contenu. la div
contient trois éléments {{htmlelement("article")}} , qui constitueront les panneaux de contenu correspondant à chaque onglet. Chaque panneau contient un échantillon de contenu.
L'idée ici est que nous allons donner aux onglets l'aspect d'un menu de navigation horizontal standard, et que nous allons donner aux panneaux l'aspect d'être superposés en utilisant un positionnement absolu. Nous vous donnerons également un peu de JavaScript à inclure dans votre page pour afficher le panneau correspondant lorsqu'un onglet est pressé, et nous donnerons un style à l'onglet lui-même. Vous n'aurez pas besoin de comprendre le JavaScript lui-même à ce stade, mais vous devriez penser à apprendre quelques bases de JavaScript dès que possible - plus les fonctionnalités de votre interface utilisateur deviennent complexes, plus il est probable que vous aurez besoin de JavaScript pour implémenter les fonctionnalités souhaitées.
To begin with, add the following between your opening and closing {{HTMLElement("style")}} tags:
html { font-family: sans-serif; } * { box-sizing: border-box; } body { margin: 0; }
This is just some general setup to set a sans-serif font on our page, use the border-box
{{cssxref("box-sizing")}} model, and get rid of the default {{htmlelement("body")}} margin.
Next, add the following just below your previous CSS:
.info-box { width: 450px; height: 400px; margin: 0 auto; }
This sets a specific width and height on the content, and centers it on the screen using the old margin: 0 auto
trick. Previously in the course we advised against setting a fixed height on content containers if at all possible; it is ok in this circumstance because we have fixed content in our tabs. It also looks a bit jarring to have different tabs at different heights.
Now we want to style tabs to look like tabs — basically, these are a horizontal navigation menu, but instead of loading different web pages when they are clicked on like we've seen previously in the course, they cause different panels to be displayed on the same page. First, add the following rule at the bottom of your CSS to remove the default {{cssxref("padding-left")}} and {{cssxref("margin-top")}} from the unordered list:
.info-box ul { padding-left: 0; margin-top: 0; }
Note: We are using descendant selectors with .info-box
at the start of the chain throughout this example — this is so that we can insert this feature into a page with other content already on it, without fear of interfering with the styles applied to other parts of the page.
Next, we'll style the horizontal tabs — the list items are all floated left to make them sit in a line together, their {{cssxref("list-style-type")}} is set to none
to get rid of the bullets, and their {{cssxref("width")}} is set to 150px
so they will comfortably fit across the info-box. The {{htmlelement("a")}} elements are set to {{cssxref("display")}} inline-block so they will sit in a line but still be stylable, and they are styled appropriately for tab buttons, using a variety of other properties.
Add the following CSS:
.info-box li { float: left; list-style-type: none; width: 150px; } .info-box li a { display: inline-block; text-decoration: none; width: 100%; line-height: 3; background-color: red; color: black; text-align: center; }
Finally for this section we'll set some styles on the link states. First, we'll set the :focus
and :hover
states of the tabs to look different when they are focused/hovered, providing users with some visual feedback. Secondly, we'll set a rule that puts the same styling on one of the tabs when a class
of active
is present on it. We will set this using JavaScript when a tab is clicked on. Place the following CSS below your other styles:
.info-box li a:focus, .info-box li a:hover { background-color: #a60000; color: white; } .info-box li a.active { background-color: #a60000; color: white; }
The next job is to style our panels. Let's get going!
First, of all, add the following rule to style the .panels
{{htmlelement("div")}} container. Here we simply set a fixed {{cssxref("height")}} to make sure the panels fit snugly inside the info-box, {{cssxref("position")}} relative
to set the {{htmlelement("div")}} as the positioning context, so you can then place positioned child elements relative to it and not the {{htmlelement("html")}} element, and finally we {{cssxref("clear")}} the float set in the CSS above so that it doesn't interfere with the remainder of the layout.
.info-box .panels { height: 352px; position: relative; clear: both; }
Finally for this section, we will style the individual {{htmlelement("article")}} elements that comprise our panels. The first rule we'll add will absolutely {{cssxref("position")}} the panels, and make them all sit flush to the {{cssxref("top")}} and {{cssxref("left")}} of their {{htmlelement("div")}} container — this part is absolutely key to this whole layout feature, as it makes the panels sit on top of one another. The rule also gives the panels the same set height as the container, and gives the content some padding, a text {{cssxref("color")}}, and a {{cssxref("background-color")}}.
The second rule we'll add here makes it so that a panel with a class
of active-panel
set on it will have a {{cssxref("z-index")}} of 1 applied to it, which will make it sit above the other panels (positioned elements have a z-index
of 0 by default, which would put them below). Again, we'll add this class using JavaScript at the appropriate time.
.info-box article { position: absolute; top: 0; left: 0; height: 352px; padding: 10px; color: white; background-color: #a60000; } .info-box .active-panel { z-index: 1; }
The final step to getting this feature working is to add some JavaScript. Put the following block of code, exactly as written in between your opening and closing {{htmlelement("script")}} tags (you'll find these below the HTML content):
var tabs = document.querySelectorAll('.info-box li a'); var panels = document.querySelectorAll('.info-box article'); for(i = 0; i < tabs.length; i++) { var tab = tabs[i]; setTabHandler(tab, i); } function setTabHandler(tab, tabPos) { tab.onclick = function() { for(i = 0; i < tabs.length; i++) { tabs[i].className = ''; } tab.className = 'active'; for(i = 0; i < panels.length; i++) { panels[i].className = ''; } panels[tabPos].className = 'active-panel'; } }
This code does the following:
tabs
and panels
, so we can easily do things to them later on.for
loop to cycle through all the tabs and run a function called setTabHandler()
on each one, which sets up the functionality that should occur when each one is clicked on. When run, the function is passed a reference to the particular tab it is being run for, and an index number i
that indentifies the tab's position in the tabs
array.setTabHandler()
function, the tab has an onclick
event handler set on it, so that when the tab is clicked, the following occurs:
for
loop is used to cycle through all the tabs and remove any classes that are present on them.class
of active
is set on the tab that was clicked on — remember from earlier that this class has an associated rule in the CSS that sets the same {{cssxref("color")}} and {{cssxref("background-color")}} on the tab as the panels are styled with.for
loop is used to cycle through all the panels and remove any classes that are present on them.active-panel
is set on the panel that corresponds to the tab that was clicked on — remember from earlier that this class has an associated rule in the CSS that sets its {{cssxref("z-index")}} to 1, making it appear over the top of the other panels.That's it for the first example. Keep your code open, as we'll be adding to it in the second one.
In our second example, we will take our first example — our info-box — and add it into the context of a full web page. But not only that — we'll give it fixed position so that it stays in the same position in the browser window. When the main content scrolls, the info-box will stay in the same position on the screen. Our finished example will look like this:
Note: You can see the finished example running live at fixed-info-box.html (source code). Check it out to get an idea of what you will be building in this section of the article.
As a starting point, you can use your completed example from the first section of the article, or make a local copy of info-box.html from our Github repo.
First of all, we need some additional HTML to represent the web site main content. Add the following {{htmlelement("section")}} just below your opening {{htmlelement("body")}} tag, just before the existing section:
<section class="fake-content"> <h1>Fake content</h1> <p>This is fake content. Your main web page contents would probably go here.</p> <p>This is fake content. Your main web page contents would probably go here.</p> <p>This is fake content. Your main web page contents would probably go here.</p> <p>This is fake content. Your main web page contents would probably go here.</p> <p>This is fake content. Your main web page contents would probably go here.</p> <p>This is fake content. Your main web page contents would probably go here.</p> <p>This is fake content. Your main web page contents would probably go here.</p> <p>This is fake content. Your main web page contents would probably go here.</p> </section>
Note: You can feel free to change the fake content for some real content if you like.
Next we need to make some small changes to the existing CSS, to get the info-box placed and positioned. Change your .info-box
rule to get rid of margin: 0 auto;
(we no longer want the info-box centered), add {{cssxref("position")}}: fixed;
, and stick it to the {{cssxref("top")}} of the browser viewport.
It should now look like this:
.info-box { width: 450px; height: 400px; position: fixed; top: 0; }
The only thing left for this example is to provide the main content with some styling. Add the following rule underneath the rest of your CSS:
.fake-content { background-color: #a60000; color: white; padding: 10px; height: 2000px; margin-left: 470px; }
To start with, we give the content the same {{cssxref("background-color")}}, {{cssxref("color")}}, and {{cssxref("padding")}} as the info-box panels. We then give it a large {{cssxref("margin-left")}} to move it over to the right, making space for the info-box to sit in, so it is not overlapping anything else.
This marks the end of the second example; we hope you'll find the third just as interesting.
The final example we'll present here is a panel that slides on and off the screen at the press of an icon — as mentioned earlier, this is popular for situations like mobile layouts, where the available screen spaces is small, so you don't want to use up most of it by showing a menu or info panel instead of the useful content.
Our finished example will look like this:
Note: You can see the finished example running live at hidden-info-panel.html (source code). Check it out to get an idea of what you will be building in this section of the article.
As a starting point, make a local copy of hidden-info-panel-start.html from our Github repo. This doesn't follow on from the previous example, so a fresh start file is required. Let's have a look at the HTML in the file:
<label for="toggle">❔</label> <input type="checkbox" id="toggle"> <aside> ... </aside>
To start with here we've got a {{htmlelement("label")}} element and an {{htmlelement("input")}} element — <label>
elements are normally used to associate a text label with a form element for accessibility purposes (allowing a screen user to see what description goes with what form element). Here it is associated with the <input>
checkbox using the for
and id
attributes.
Note: We've put a special question mark character into our HTML to act as our info icon — this represents the button that will be pressed to show/hide the panel.
Here we are going to use these elements for a slightly different purpose — another useful side effect of <label>
elements is that you can click a checkbox's label to check the checkbox, as well as just the checkbox itself. This has led to the well-known checkbox hack, which provides a JavaScript-free way of controlling an element by toggling a button. The element we'll be controlling is the {{htmlelement("aside")}} element that follows the other two (we've left its contents out of the above code listing for brevity).
In the below sections we'll explain how this all works.
First let's deal with the form elements — add the following CSS in between your {{htmlelement("style")}} tags:
label[for="toggle"] { font-size: 3rem; position: absolute; top: 4px; right: 5px; z-index: 1; cursor: pointer; } input[type="checkbox"] { position: absolute; top: -100px; }
The first rule styles the <label>
; here we've:
absolute
on it, and used {{cssxref("top")}} and {{cssxref("right")}} to position it nicely in the top-right corner.The second rule sets {{cssxref("position")}} absolute
on the actual checkbox <input>
element, and hides it off the top of the screen. We don't actually want to see this on our UI.
Now it's time to style the actual sliding panel itself. Add the following rule to the bottom of your CSS:
aside { background-color: #a60000; color: white; width: 340px; height: 100%; padding: 0 20px; position: fixed; top: 0; right: -370px; transition: 0.6s all; }
There's a lot going on here — let's discuss it bit by bit:
: fixed;
on the panel so it will always appear in the same place, even if the page has content to scroll. We glue it to the {{cssxref("top")}} of the viewport, and set it so that by default it is offscreen to the {{cssxref("right")}}.<label>
will check the associated checkbox! We told you it was a hack.) You will learn a lot more about...There is one final bit of CSS to add — put the following at the bottom of your CSS:
input[type=checkbox]:checked + aside { right: 0px; }
The selector is pretty complex here — we are selecting the <aside>
element adjacent to the <input>
element, but only when it is checked (note the use of the {{cssxref(":checked")}} pseudo-class to achieve this). When this is the case, we are setting the {{cssxref("right")}} property of the <aside>
to 0px
, which causes the panel to appear on the screen again (smoothly due to the transition). Clicking the label again unchecks the checkbox, which hides the panel again.
So there you have it — a rather clever JavaScript-free way to create a toggling button effect. This will work in IE9 and above (the smooth transition will work in IE10 and above.) This effect does have some concerns — this is a bit of an abuse of form elements, as they weren't intended for this purpose. In addition, the effect is not great in terms of accessibility; the label is not focusable by default, and the non-semantic use of the form elements could cause issues with screen readers. JavaScript and a link or button might be more appropriate, but it is still fun to experiment with.
So that rounds off our look at positioning — by now, you should have an idea of how the basic mechanics work, as well as understanding how to start applying these to build some interesting UI features. Don't worry if you didn't get this all immediately — positioning is a fairly advanced topic, and you can always work through the articles again to aid your understanding. The next subject we'll turn to is Flexbox.