Positionnement d'une page html par css =========================================== Ce document résume quelques notions pour le positionnement des objets html à l'aide d'un fichier css. En théorie, il y a une documentation complète en ligne. En pratique, c'est souvent assez pénible car la documentation est souvent évasive. On peste en se demandant ou est décrit le fichu algorithme utilisé. Cher lecteur, ce document est pour toi si comme moi tu as peiné plusieurs jours avec des objets dont le positionnement saute de façon erratique quand tu as changé un paramètre, si tu cherches à connaître l'algorithme de positionnement utilisé par le navigateur. Le type d'objets a placer --------------------------- Il y a plusieurs types d'images qui apparaissent dans une page web, au sens ou les règles de postionnement qu'on leur applique sont différentes : - les images qui fixent le cadre et sont fixes indépendamment des modifications ultérieures du contenu - les images qui s'inscrivent dans un flot texte-image et sont placées au gré du texte. - les elements décoratifs attachés a un contenu ( exemple: un logo de crayon en haut de chaque article ) Il y a aussi plusieurs types de positionnement pour un texte: - le texte fixe ( Titre d'Accueil de la page web, menus...) - le texte en flot, en général actualise' au fur et à mesure des ajouts du site Il y a enfin - Des textes et images qui restent toujours a la meme place sur l'ecran pour rester visibles ( par exemple un menu qui reste visible meme si on bouge l'ascenceur). Il faut mettre les objets précédents en relation avec les options de positionnement adéquates de css. De la racine vers les feuilles, avec les marqueurs -------------------------------------------------- L'algorithme de positionnement utilisé par le navigateur qui va afficher la page web est le suivant. Le navigateur construit l'arbre d'objets de la page. Il positionne les objets en commencant par la racine et en finissant aux feuilles, en explorant toute la branche en profondeur avant de passer à la branche voisine. Lors de cette exploration de l'arbre, le positionnement de chaque objet rencontré dépend du marqueur de position associé à l'objet. Chaque objet est muni d'un marqueur de position sous la forme d'un attribut *position:valeur*, où valeur est choisie parmi les quatre possibilités suivantes: - *static* ( = le défaut) - *absolute*, - *relative*, - *fixed*. Les valeurs *initial* et *inherit* sont également possibles, mais elles redonnent après calcul l'une des quatre possibilités précédentes. Le positionnement des *static* ------------------------------- Si le navigateur doit placer un objet "static", il va essayer de le poser en n'empiétant pas sur les autres objets *static* et *relative* déjà posés. En revanche, le navigateur ne se préocuppe pas du chevauchement des objets *static* avec les objets *absolute* ou *fixed*. Autrement dit, les objets absolus ou fixed sont "inconnus/transparents" pour les objets static. Le navigateur commence par calculer la taille de l'objet *static* qu'il cherche à poser. Il ajoute à cette taille les valeurs des paramètres *padding* et *border-width* (si *border-style* n'est pas positionné à *none*). Cet objet dont la taille est maintenant connu doit maintenant être posé dans une boite contenante. Cette boite contenante est est déterminée: c'est un objet *div*, et parmi tous les *div* de l'arbre, on choisit l'ancêtre le plus proche du *static* qu'on veut poser. En l'absence d'ancêtre, c'est le document qui sert de div par défaut. La boite conteneur maintenant déterminée contient déja des objets *static* et *relative*. Ce sont des objets qui sont plus proches de la racine et qui ont dejà été traités par le navigateur dans les étapes précédentes de l'algorithme. Ce peuplement laisse 2 empreintes dans la boite. La petite empreinte e est formée par les objets déposés dans la boite. La grande empreinte E est formée par les objets déposés *aggrandis de leurs marges*. L'objet static qu'on veut poser admet de meme deux empreintes o et O, petites et grande, sans ou avec les marges. L'objet nouvellement posé devra satisfaire les 2 conditions suivantes: o et E ne se rencontrent pas, O et e ne se rencontrent pas. En d'autres termes, aucun objet ne doit chevaucher un autre objet ni sa marge. Parmi toutes les possibilités de placement respectant ce critère, l'algorithme procède pour les objets qui ont la propriété *display:inline* de la même facon que lorsqu'on pose une nouvelle lettre sur une feuille de papier quand on est en train d'écrire. On cherche une place libre de la gauche vers la droite, avec passage a la ligne et retour à la gauche de la boite quand la ligne est pleine. Pour un objet ayant la propriété *display:block* au lieu de *display:inline* un retour à la ligne est imposé avant de rechercher une place libre pour poser l'objet, à la manière d'une lettre sur une feuille de papier quand on commence un nouveau paragraphe. Par exemple, les eléments *
  • * d'une liste se voient attribuer par défaut *display:block*. En conséquence, chaque nouvel élément d'une liste engendre automatiquement un passage à la ligne. On peut changer la propriété en *display:block* si on a besoin de présenter une liste horizontalement dans un menu sans retour à la ligne. La propriété *display:inline-block* permet de placer les éléments comme avec *display:inline* tout en conservant la structure de bloc. Concrètement, avec *display:inline-block*, les propriétés *width:value* et *height:value* sont prises en compte, alors qu'elles sont sans effet pour les objets *display:inline*. En termes intuitifs, cela signifie qu'un élement *inline* est applati pour entrer comme dans un interligne, tandis qu'un element *inline-block* est positionné comme une lettre usuelle sans passage à la ligne, mais conserve sa géométrie de bloc. Si l'objet a poser a l'attribut *float:none*, le navigateur pose le nouvel objet dès qu'il trouve une place libre comme décrit précédemment. Si *float=left* ou *float=right*, la position ainsi trouvée par l'étape précédente n'est qu'une position intermédiaire. On poursuit avec un decalage maximal vers la gauche ou vers la droite si un tel decalage est possible. En termes techniques et inambigus. ce procédé se décrit ainsi pour placer un objet de propriétés *position:static*, *display:inline*. On note (a,b)=(coordonnee ligne,coordonnee colonne) les coordonnees du coin haut gauche du dernier objet non flottant pose' dans la div ( a,b=0,0 si on n'a pas encore posé d'objet). Le coin haut gauche du nouvel objet sera place' plus bas, c'est a dire en (c,d) avec c>=a. On choisit c minimum avec c>=a de sorte que la place libre sur la ligne de hauteur c soit assez grande pour poser l'objet. Si float = left, on choisit d minimal. Si float=right, on choisit d maximal. Si float=none et c=a, on choisit d minimal parmi les d>=b. Si float=none et c>a, on choisit d minimal parmi les d>=0. En résumé, le positionnement des objets ayant *position:static* dépend du contenant et des propriétés de l'objet lui même (*float* ou pas, valeur de la propriété *display*...) en suivant globalement la paradigme des lettres qu'on écrit sur une feuille. Il est possible aussi d'utiliser d'autres paradigmes pour positionner des *static* dans un *div*, notamment en affectant la propriété *display:flex* au *div* conteneur. Je ne développe pas, mais ca peut être intéressant à explorer si le paradigme de l'ecriture se révèle inadapté, par exemple quand on veut poser les objets dans la *div* en écrivant de bas en haut ou de droite à gauche, ou que l'on veut mettre des espaces entre des mots pour remplir la ligne entièrement. Le positionnement des objets *positionnés* ------------------------------------------ On dit par definition qu'un élement qui n'a pas la position "static" qu'il est "positionné". Nous avons décrit le positionnement des objets *static*. Il reste à voir le positionnement des objets positionnés. Les ojbets positionnés sont munis d'attributs *top:value*, *right:value*, *left:value*, *bottom:value* qui permettent d'affiner le placement. Ces paramètres de positionnement *top,right,left,bottom* sont ignorés dans le cas d'un objet *static*. Pour un objet dont le positionnement est *position:relative*, le navigateur calcule d'abord le positionnement comme dans le cas *position:static*. Puis l'objet est décalé de la valeur des parametres de positionnement *left,right, bottom, top* Si un objet a position:absolute, la boite contenante n'est pas la même que dans les cas précédents. Le navigateur commence par rechercher le dernier *div* ancestral qui est un objet positionné. Si tous les *div* qui sont des aieux ont une position *position:static*, le div par défaut est la fenêtre d'affichage du navigateur (En particulier, dans ce cas, le redimensionnement du document ne changera pas la place de l'objet !). La boite ainsi définie sert de boite contenante et l'objet *absolute* sera placé dans cette boite contenante à l'aide des paramètres de position. Par exemple, si les paramètres *left,bottom* sont déclarés, la mesure se fait à partir de la gauche et du bas de cette boite contenante. Le positionnement dit *absolute* n'est donc pas absolu. Il est relatif à la boite contenante correspondant à la dernière boite ancestrale positionnée. Ce n'est que si cette boite ancestrale est absente que le positionnement est absolu par rapport à la fenêtre du navigateur. Si un objet est positionné par *position:fixed*, les paramètres de positionnement son interprétés par rapport à la fenetre du navigateur (=mode sticky). C'est donc comme le mode *position:absolute* dans le cas ou l'objet absolu n'a pas de boite ancestrale positionnee. Chevauchements --------------- Pour régler les priorités lors des chevauchement des objets qui partagent une partie de l'écran, on dispose de la variable z-index. Choix de positionnement pour les objets --------------------------------------- Voici quelques possibilités pour mettre en oeuvre les elements css précédents en fonction des types d'objets rencontrés. - les objets "sticky" auront *position:fixed*. Exemple: un menu toujours visible, même quand on bouge l'ascenseur pour faire défiler la page. Les parents eventuels et le contexte n'ont pas d'influence. - Les objets fixes dans le document auront *position:absolute*. Ils sont soit orphelins, soit ont des parents qui sont eux-meme dans une position qui n'est pas susceptible de bouger. - Les objets qu'on souhaite localiser dans une *zone d'accueil* de la page et qui ont le droit de bouger dans cette zone d'accueil. On fait un *div* de la taille adéquate pour decrire la zone d'accueil et on décrit les objets de la zone d'accueil comme des descendants de ce *div*. On peut déclarer ces objets en static. Si les marges ou autres petits problèmes induisent un placement difficile, on peut utiliser *position:relative* pour ajouter des petits decalages. - Les objets décoratifs qui suivent un contenu variable. Exemple: une plume d'écrivain comme logo a droite de chaque article de longueur variable. L'article est inclus dans un *div*. L'élément décoratif (ici la plume) est inclus dans le même *div* avec *position:absolute* ( exemple pour la plume: right:0px top:50% ). Le *div* parent sera positionné ( c'est à dire non *static*) puisque les absolute choisissent leur boite contenant seulement parmi ascendants positionnés. Au besoin, on remplacera le positionnement *static* du *div* parent par un *position:relative* en laissant les paramètres top/left... à zéro. - Les objets alignés ou plus généralement en position précise les uns par rapport aux autres doivent tous être en position absolue et avoir le même ancêtre positionné (cet ancetre étant eventuellement non existant). Choix des unite's ------------------ Je préfère mettre des unite's fixes plutot que des pourcentages. Les unités fixes se comportent bien quand on zoome ou dézoome sur une page. Les alignements son respectés. Si on mélange pourcentage et des donnees fixes, ça met parfois la pagaille, notamment pour des photos qui sont parfois exprimees en pourcentage de leur taille initiale. Les pourcentages restent indispensables quand on veut mettre une image au milieu d'une colonne dont on ne connait pas la longueur par exemple. Quelques details utiles ------------------------- Ne pas oublier de mettre *height:auto* aux *div* si on souhaite un redimensionnement convenable pour contenir les dessins (*static* et *relative*, non flottants) qui y sont inclus. S'il reste des problemes, ajuster avec la commande overflow.