web-dev-qa-db-fra.com

Est-il possible de conserver la largeur de l'élément parent lorsque la position: fixed est appliquée?

Lorsque nous appliquons position:fixed à un élément, il est pris dans le flux normal du document, il ne respecte donc pas la largeur de l'élément de son parent. Existe-t-il un moyen de le faire hériter de la largeur de son parent si celle-ci est déclarée sous forme de pourcentage ? (cas d'utilisation de travail ci-dessous)

let widthis = $('.box').width();
$('.dimensions').text(`width is ${widthis}`);

$('button').on('click', function() {
  $('.box').toggleClass('fixed');
  let widthis = $('.box').width();
  $('.dimensions').text(`width is ${widthis}`);
});
.container {
  max-width: 500px;
  height: 1000px;
}

.box {
  background-color: lightgreen;
}

.fixed {
  position: fixed;
}

.col-1 {
  border: 1px solid red;
  float: left;
  width: 29%;
}

.col-2 {
  border: 1px solid pink;
  float: left;
  width: 69%;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Click this to toggle position fixed for the left column</button>
<div class="container">
  <div class="col-1">
    <div class="box">
      fixed content<br>
      <span class="dimensions"></span>
    </div>
    </div>
  
  <div class="col-2">
    some other content
    </div>
  </div>
42
George Katsanos

C'est un défi intéressant. Pour aborder cela, nous devons d’abord comprendre ce que fixed fait réellement.

Comprendre fixe

Contrairement à absolute, fixedne se positionne pas par rapport à son parent le plus proche parent. Au lieu de cela, fixedse positionne par rapport à la fenêtre d'affichage. La fenêtre reste toujours fixe, c'est pourquoi vous obtenez l'effet que vous avez.

Cela dit, chaque fois que vous "héritez" d'une largeur quelconque, celle-ci sera respectée par la fenêtre d'affichage. Donc, cela ne nous sert à rien lorsque nous essayons de définir la largeur de notre élément cible à la largeur de son parent.

En savoir plus sur les différents comportements de position .

Solutions rapides

Il existe deux approches pour résoudre ce problème.

CSS pur

Nous pouvons utiliser pure CSS pour résoudre ce problème, mais nous aurions besoin de connaître la largeur à l'avance. Supposons que son élément parent est 300px;

.parent{
    width: 300px;
}

.parent .fixed_child{
    position: fixed;
    width: 300px;
}

JS

Maintenant, avec appareils mobiles, nous n'avons pas vraiment nous avons le luxe d'avoir set widths, en particulier tout ce qui dépasse 300px. L'utilisation de pourcentages ne fonctionnera pas non plus, car ce sera relatif à la fenêtre d'affichage et non à l'élément parent. Nous pouvons utiliser JS, dans ce cas avec jQuery pour y parvenir. Jetons un coup d'oeil à une fonction qui déterminera toujours la largeur de la paren t au moment donné:

 function toggleFixed () {
      var parentwidth = $(".parent").width();      
      $(".child").toggleClass("fixed").width(parentwidth);        
  }

css:

.fixed{
    position:fixed;
}

Afficher dans CodePen

Largeurs Dynamiques

C'est bien beau, mais que se passe-t-il si la largeur de la fenêtre change alors que l'utilisateur est toujours sur la page, change l'élément parent avec ceci? Tandis que le parent peut ajuster sa largeur, l'enfant conserve la largeur définie par la fonction. Nous pouvons résoudre ce problème avec écouteur d'événementresize() de jQuery. Nous devons d’abord scinder la fonction créée en deux:

function toggleFixed() {
   adjustWidth();
   $(".child").toggleClass("fixed");
 }

 function adjustWidth() {
   var parentwidth = $(".parent").width();
   $(".child").width(parentwidth);
 }

Maintenant que nous avons séparé chaque partie, nous pouvons les appeler individuellement, nous allons inclure notre méthode de bouton originale qui bascule les valeurs fixed et width:

$("#fixer").click(
     function() {
       toggleFixed();
     });

Et maintenant, nous ajoutons également l'écouteur d'événement resize à la fenêtre:

 $(window).resize(
     function() {
       adjustWidth();
     })

Afficher dans CodePen

Là! Nous avons maintenant un élément fixe dont la taille sera ajustée lorsque la fenêtre sera redimensionnée.

Conclusion

Nous avons relevé ce défi en comprenant la position fixed et ses limites. Contrairement à Absolute, fixed ne concerne que le port d'affichage et ne peut donc pas hériter de la largeur de son parent.

Pour résoudre ce problème, nous devons utiliser une certaine magie JS, qui ne prenait pas beaucoup avec jQuery, pour y parvenir.

Dans certains cas, nous avons besoin d’une approche dynamique avec des dispositifs d’échelle de différentes largeurs. Encore une fois, nous avons adopté l'approche JS.

29
Philll_t

Vous pouvez utiliser width:inherit. Cela le fera écouter au parent. Je le teste et cela fonctionne dans Firefox.

11
egon12

La largeur change parce que l'objet lorsque statique reçoit son pourcentage de largeur de son parent. Une fois que vous définissez l'objet sur fixed, il n'est plus en flux et redimensionne. 

Vous devrez définir lui-même une taille pour votre menu de navigation et ne pas vous attendre à ce que l'élément obtienne sa largeur à partir du parent.

.nav {
    position: fixed;
    width: 20%;
    border: 1px solid green;
    padding: 0px;
    list-style-type:none;
    background:lightblue;
}

http://tinker.io/3458e/5

5
Michael Rader

Bonjour, vous pouvez également utiliser jQuery pour conserver la largeur. Par exemple:

jQuery(function($) {
    function fixDiv() {
        var $cache = $('#your-element');
        var $width = $('#your-element').parent().width();
        if ($(window).scrollTop() > 100) {
            $cache.css({
                'position': 'fixed',
                'top': '10px',
                'width': $width
            });
        } else {
            $cache.css({
                'position': 'relative',
                'top': 'auto'
            });
        }
    }
    $(window).scroll(fixDiv);
    fixDiv();
 });
4
khoekman

Cela est probablement dû à une marge ou un remplissage par défaut sur l'élément <html> ou <body>. Lorsqu'il est statique, sa taille est basée sur la largeur du <body> à ce moment-là, mais lorsqu'il passe à position:fixed, il est dimensionné par rapport à la fenêtre d'affichage.

En tant que tel, supprimer cette marge/remplissage par défaut devrait résoudre le problème (selon mon expérience, body { margin:0; } le résout), tout comme le fait de modifier le dimensionnement lorsqu'il est corrigé (comme width:calc(n% - 5px);).

3
Zach Saucier

Comme quelqu'un le suggère déjà, l'utilisation de javascript est la meilleure solution.

Sans jQuery.

const parentElement = document.querySelector('.parent-element');
const fixedElement = document.querySelector('.fixed-element');

// get parent-element width when page is fully loaded
// and change fixed-element width accordingly
window.addEventListener('load', changeFixedElementWidth);

// get parent-element width when window is resized
// and change fixed-element width accordingly
window.addEventListener('resize', changeFixedElementWidth);

function changeFixedElementWidth() {
  const parentElementWidth = parentElement.getBoundingClientRect().width;
  fixedElement.style.width = parentElementWidth + 'px';
}
2
pldg

Une solution de contournement pourrait être: left:8px; right:0; width:18%; dans le CSS pour le nav . Pas la meilleure solution cependant.

0
Simke Nys