Is it possible to keep the width of the parent element when position: fixed is applied?
Asked Answered
G

10

70

When we apply position:fixed to an element, it's taken out of the normal flow of the document, therefore it doesn't respect it's parent's element width. Are there ways to make it inherit it's parent's width if this is declared as a percentage ? (working use case below)

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>
Gadoid answered 15/4, 2013 at 15:2 Comment(8)
The CSS looks like it's doing what it's told to do?Boccherini
it, could also be that the menu is not the parent anymore?Boccherini
I updated the url, I had forgot some CSS Properties in my test case.. Change position:fixed with position:static and you will see how the width changes.Gadoid
Yes, its probably because the menu is not acting as the parent anymore, i think you may have to adjust accordingly.Boccherini
can you be a bit more specific?:)Gadoid
Ok, well just like when you use a float or position:absolute, you notice when using floats sometimes the parents height drops and doesn't wrap around the floated children, its because the parent doesn't know that the child is still there, that's why with your position:fixed; the element is really no longer a child of the menu and therefor doesn't listen to the parent any more, so basically you will have to set the width to something specific, this may be the only workaroundBoccherini
@Boccherini 3 years later, maybe there's some workaround :) (flexbox, calc() ?)Gadoid
@GeorgeKatsanos, I think maybe the time has come to choose an answer?Hurrah
H
61

This is an interesting challenge. To approach this, we should first understand what fixed actually does.

Understand Fixed

Unlike absolute, fixed doesn't position itself from its closest relative parent. Instead, fixed positions itself relative to the viewport. The viewport will always stay fixed, which is why you get the effect that you do.

That being said, whenever you "inherit" any width it will be respective to the viewport. So it does us no good when we're trying set the width of our target element to the width of it's parent.

Learn more about the different behaviors of position.

Quick Solutions

There are two approaches to fix this.

Pure CSS

We can use pure CSS to fix this problem, but we would need to know the width in advance. Suppose that its parent element is 300px;

.parent{
    width: 300px;
}

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

JS

Now with mobile devices, we don't really have the luxury of having set widths, especially anything over 300px. Using percentages won't work either, since it will be relative to the viewport and not the parent element. We can use JS, in this case with jQuery to achieve this. Lets take a look at a function that will always set the width of the parent at the given moment:

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

css:

.fixed{
    position:fixed;
}

View in CodePen

Dynamic Widths

That's fine and dandy, but what happens if the width of the window changes while the user is still on the page, changing the parent element with this? While the parent may adjust its width, the child will stay the set width that the function set it. We can fix this with jQuery's resize() event listener. First we'll need to split the function we created into two:

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

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

Now that we've separated each part, we can call them individually, we'll include our original button method that toggles the fixed and width:

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

And now we also add the resize event listener to the window:

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

View in CodePen

There! Now we have a fixed element who's size will be adjusted when the window is resized.

Conclusion

We've tackled this challenge by understanding fixed position and it's limitations. Unlike Absolute, fixed only relates to the view port and therefore cannot inherit its parent's width.

To solve this, we need to use some JS magic, which didn't take very much with jQuery, to achieve this.

In some cases, we need a dynamic approach with scaling devices of varying widths. Again, we took the JS approach.

Hurrah answered 19/3, 2017 at 8:52 Comment(5)
This is an outstanding answer. You've just earned the Outstanding Answer Hat!Sondrasone
what about width: inherit; ?Nell
> That being said, whenever you "inherit" any width it will be respective to the viewport. So it does us no good when we're trying set the width of our target element to the width of it's parent.Hurrah
Awesome answer! Saw so many wrong answers to this question...Seeder
Also good to note that an element with position: fixed will set its position to a parent instead of the viewport if that parent element has a transform applied. This one threw me once.Suggest
A
14

You can use width:inherit. This will make it listen to parent. I test it and it works in Firefox.

Amado answered 2/6, 2013 at 19:44 Comment(1)
This doesn't always work. Sometimes the fix is what I suggestedSuccinct
M
7

The width is changing because the object when static is receiving its percentage width from its parent. Once you set the object to fixed it is no longer in flow and resizes.

You're gonna have to set a size to your nav menu on its own and not expect the element to get its width from the parent.

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

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

Morrow answered 15/4, 2013 at 15:12 Comment(1)
I updated the url, I had forgot some CSS Properties in my test case.. Change position:fixed with position:static and you will see how the width changes.Gadoid
A
5

As someone already suggest, using plain javascript (without jquery):

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

window.addEventListener('load', changeFixedElementWidth);
window.addEventListener('resize', changeFixedElementWidth);

function changeFixedElementWidth() {
  const parentElementWidth = parentElement.getBoundingClientRect().width;
  fixedElement.style.width = parentElementWidth + 'px';
}
Apportionment answered 26/2, 2018 at 2:7 Comment(0)
W
4

Hi you could also use jquery to keep the width. For example:

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();
 });
Wigan answered 9/7, 2015 at 10:12 Comment(1)
would like to avoid JS for this.Gadoid
S
3

This is likely because of some default margin or padding on the <html> or <body> element. When it's static, it sizes based on the <body>'s width at the time, but when it changes to position:fixed it's sized in respect to the viewport.

As such, removing that default margin/padding should fix the problem (in my experience body { margin:0; } fixes it) as should changing the sizing when it is fixed (like width:calc(n% - 5px);).

Succinct answered 3/5, 2015 at 1:58 Comment(2)
what does "n" stand for?Gadoid
@GeorgeKatsanos Whatever percentage width you want the element to beSuccinct
D
0

A workaround might be: left:8px; right:0; width:18%; in the CSS for the nav. Not the best solution though.

Dialogist answered 15/4, 2013 at 15:26 Comment(1)
yeah, setting arbitrary numbers is a bit of a hack - I guess the only solution seems to be getting the parent's width with javascript..Gadoid
E
0

In my case, I wanted a responsive UI, but I also want a fixed sidebar. What I did was find the maximum width on the largest screen in pixels (250px in my case). Then I used:

<script>
.parent {
  maxWidth: '1500px';
  margin: 'auto auto';
}
.left {
  flex: 1;
}
.center {
  flex: 4;
}
.right {
  flex: 1;
}
.fixedTop {
  position: 'fixed';
  maxWidth: '250px';
}
</script>

<div className="parent">
  <div className="left">left side</div>
  <div className="center">center</div>
  <div className="right"> 
    <div className="fixedTop">
      <label>I am responsively sized horizontally up to my max width.</label>
    </div>
  </div>
</div>

This does not allow you to inherit width as requested, but it may help avoid that need if you are trying to do what I did.

Elisha answered 2/2, 2023 at 16:6 Comment(0)
G
0

I was here on this thread at first, but my problem was not solved, so I did a work around myself amnd it worked in my case. here it is..

` .parent{ position: "sticky"; top, right, bottom, left: // adjust distance from sides so that it will be like in fixed position }

.child{ width:"100%" } `

Gambrinus answered 11/2, 2023 at 12:40 Comment(0)
R
-3

Add width:auto; to the element with position:fixed; to make its width equal to the width of its parent element.

Ridgley answered 15/1, 2016 at 10:59 Comment(2)
Not sure why this got downvoted--it actually fixed my problem. Thanks!Compromise
it does not work. with position: fixed the element is out of the normal flow and it doesn't respect it's parent width.Gadoid

© 2022 - 2024 — McMap. All rights reserved.