Setting the positioned fixed element width of the parent div not working

Viewed 1558

I am trying to fix position element, and to take the full width of the parent div. This is my html:

     <div class="col-md-3">
        <div class="player-avatar-card">
          <div class="card-body">
            <div class="avatar-image">
              <img src="/imagecache/small/{{ $player->image_filename }}" alt="Profile Image" class="rounded-circle">
              <img class="flag rounded-circle" src="/icons/flags-round/{{ $player->nationality }}.svg"></h3>
            </div>
            <h5>{{ $player->first_name }} {{ $player->last_name }}</h5>
            <p>{{ $player->nationality }}, {{ $player->age }} years</p>
            <div class="social-buttons">
              <div class="col-12">
                <a class="btn btn-info btn-lg" href="#" role="button">
                  <i class="ion-plus-round"></i> follow</a>
              </div>
              <div class="col-12">
                <a class="btn btn-info btn-outline-info" href="#" role="button">
                  <i class="ion-android-share-alt"></i> share</a>
              </div>
            </div>
          </div>
        </div>
      </div>

I am giving the position fix class to player-avatar-card, on scrolling to element:

  const avatarCard = document.querySelector('.player-avatar-card');
  const fixClassAvatar = 'is-fixed-avatar';

  function stickyScroll() {
    if( window.pageYOffset > 56 ) {
      avatarCard.classList.add(fixClassAvatar);
    }
    if( window.pageYOffset < 56 ) {
      avatarCard.classList.remove(fixClassAvatar);
    }
  }
  $(window).scroll(stickyScroll);

And this is the class:

.is-fixed-avatar {
  position: fixed;
  max-width: inherit;
  width: 100%;
}

But, the element goes out of the col-md-3 div, how can I fix that?

Here is the fiddle. Make sure to expand it on the screen, so that it is wide enough to see it working.

2 Answers

If you use position: fixed, the div is taken out of the flow and consequently taken out of the col-md-3 div. I propose to make it absolute:

.profile-content .player-info .is-fixed-avatar {
  position: absolute;
  left: 0;
  right: 0;
}

Now you can use jQuery to place some stickiness to the avatar - check it by minimising the window height. See a simplified demo below (the last section-card is inside the col-md-9):

$(document).ready(function() {
  const avatar = $('.player-avatar-card');
  const avatarBox = avatar.parent();

  function sticky() {
    var offset = avatarBox.offset().top - $(window).scrollTop();
    if (offset >= 0) {
      avatar.css('top', '0');
      return;
    }
    avatar.offset({
      'left': avatar.offset().left,
      'top': -offset + 90 // 90px to adjust for padding
    });
  }
  $(window).scroll(sticky);
});
body {
  background: #fff;
  color: #484848 !important;
}

.is-fixed {
  position: fixed;
  left: 0;
  right: 0;
  z-index: 10;
  top: 0;
}

.page-nav {
  height: 56px;
  border-bottom: 1px solid #f1eeee;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.1);
  background: #fff;
}

.page-nav .section-links .active {
  border-bottom: 2px solid #008489;
  color: #008489;
  font-weight: 500;
}

.page-nav .nav {
  height: 56px;
  display: -webkit-box;
  display: flex;
  -webkit-box-align: center;
  align-items: center;
}

.page-nav .nav .nav-link {
  height: 56px;
  display: -webkit-box;
  display: flex;
  -webkit-box-align: center;
  align-items: center;
  min-width: 100px;
  -webkit-box-pack: center;
  justify-content: center;
  color: #484848;
}

.lg-strong-font {
  font-size: 34px;
  font-weight: 500;
  color: #e90052;
}

.lg-strong-font span {
  font-size: 1rem;
}

.profile-content {
  padding: 2rem 0;
  background: #f7f7f7;
}

.profile-content .info-content {
  padding-left: 3rem;
  padding-right: 3rem;
}

.profile-content .title-margin {
  margin-bottom: 1.5rem;
}

.profile-content .title-icon {
  color: #008489;
  margin-right: 1.7rem;
  margin-left: 2px;
}

.profile-content .info-title-hr {
  margin-left: 3rem;
  margin-right: 3rem;
}

.profile-content .section-card {
  margin-top: 1.5rem;
  background: #fff;
  padding: 1.5rem;
  border: 1px solid #f1eeee;
}

.profile-content .sub-section {
  margin-top: 2rem;
}

.profile-content .icon-wrapper {
  width: 30px;
  height: 30px;
  display: -webkit-box;
  display: flex;
  -webkit-box-align: center;
  align-items: center;
  -webkit-box-pack: center;
  justify-content: center;
}

.profile-content .icon-wrapper i {
  color: #008489;
}

.profile-content .video-section {
  margin: 0;
  margin-left: -5px;
}

.profile-content .video-section .profile-video-box {
  padding: 0;
  padding-left: 5px;
  margin-bottom: 10px;
}

.profile-content .player-info .icon-box {
  padding-right: 0;
  padding-top: 8px;
}

.profile-content .player-info .player-info-card-content {
  margin-top: 0;
}

.profile-content .player-info .is-fixed-avatar {
  position: absolute;
  left: 0;
  right: 0;
}

.profile-content .player-info .player-avatar-card {
  display: -webkit-box;
  display: flex;
  -webkit-box-pack: center;
  justify-content: center;
  text-align: center;
  padding: 1.5rem 0;
  border: 1px solid #f1eeee;
  background: #fff;
}

.profile-content .player-info .player-avatar-card .card-body {
  width: 100%;
}

.profile-content .player-info .player-avatar-card p {
  margin-bottom: 0.2rem;
  font-size: 0.8rem;
  color: #7b7b7b;
}

.profile-content .player-info .player-avatar-card .avatar-image {
  position: relative;
  margin-bottom: 1.5rem;
  display: inline-block;
}

.profile-content .player-info .player-avatar-card .avatar-image img {
  width: 120px;
  height: 120px;
}

.profile-content .player-info .player-avatar-card .avatar-image .flag {
  position: absolute;
  bottom: 10px;
  right: -5px;
  width: 35px;
  height: 35px;
  border: 3px solid #fff;
}

.profile-content .player-info .player-avatar-card .icon {
  width: 30px;
  height: 30px;
  margin-right: 5px;
}

.profile-content .player-info .player-avatar-card .card-title {
  margin: 0.5rem 0;
}

.profile-content .player-info .social-buttons {
  margin-top: 1rem;
}

.profile-content .player-info .social-buttons .btn {
  border-radius: 200px;
  font-weight: 500;
  margin: 0.5rem;
}

.profile-content .player-info .social-buttons .btn i {
  margin-right: 10px;
}

.profile-content .table>thead>tr>th,
.profile-content .table>tbody>tr>th,
.profile-content .table>tfoot>tr>th,
.profile-content .table>thead>tr>td,
.profile-content .table>tbody>tr>td,
.profile-content .table>tfoot>tr>td {
  line-height: 1.42857143;
  vertical-align: top;
  border: 0 !important;
}

.profile-content .table>thead>tr>th {
  text-align: center;
}

.profile-content .table>thead>tr>th .icon-wrapper {
  margin: auto;
}

.profile-content .table>thead>tr>th,
.profile-content .table>tbody>tr>td {
  max-width: 110px !important;
  vertical-align: middle;
}

.profile-content .table>thead {
  border-bottom: 1px solid #f1eeee;
  background: #fff;
}

.profile-content .table-responsive {
  margin-bottom: 0;
}

.profile-content .no-data-message {
  margin-top: 1.5rem;
}

.profile-content .years {
  font-size: 14px;
  font-weight: 500;
}

.profile-content .info-label {
  font-weight: 400;
  font-size: 0.8rem;
  color: #7b7b7b;
}

footer {
  height: 20rem;
  padding: 20px 0;
  position: relative;
  z-index: 1;
  display: -webkit-box;
  display: flex;
  -webkit-box-align: center;
  align-items: center;
  background-color: #fff;
  color: #3c3e42;
  border-top: 1px solid rgba(204, 204, 204, 0.4);
}

footer h4 {
  font-weight: 700;
}

footer a {
  display: block;
  font-weight: 500;
  margin-bottom: 10px;
}

.search-result {
  margin-top: 2rem;
}

.search-result .search-list {
  margin-top: 1rem;
}

.search-result .query-card {
  color: #fff;
  background: #00bcd4;
}

.search-result .query-card .card-block {
  padding: 1rem;
}

.search-result .search-list-media .media img {
  width: 160px;
  height: auto;
}

.search-result .media {
  margin-top: 10px !important;
}

.search-result .media-body p {
  margin: 0 !important;
  padding-top: 0 !important;
  padding-bottom: 0 !important;
}

.search-result .tab-content {
  padding: 1rem;
}

.search-result .pagination,
.search-result .tab-content {
  margin-top: 2rem;
}

.contact-form .card {
  padding: 1rem;
}

body {
  overflow-x: hidden;
  position: relative;
}

#wrapper {
  position: relative;
  z-index: 10;
  top: 0;
  left: 0;
  transition: all 0.4s;
}

.menu {
  position: fixed;
  z-index: 20;
  overflow: hidden;
  transition: all 0.4s;
  color: #008489;
  padding: 45px;
  padding-top: 3rem;
  background: #333;
}

.menu a {
  color: #e4e4e4;
}

.menu h4 {
  margin-top: 10px;
}

.menu .btn {
  margin-top: 1rem;
}

.push-menu-left {
  top: 50px;
  width: 280px;
  height: 100%;
  box-shadow: -4px 1px 5px 0px rgba(0, 0, 0, 0.2);
  -webkit-box-shadow: -4px 1px 5px 0px rgba(0, 0, 0, 0.2);
}

.push-menu-left {
  right: -285px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">

<div class="container-fluid page-nav">
  <div class="container">
    <div class="row">
      <div class="col-md-9 offset-md-3">
        <nav id="page-nav" class="nav section-links">
          <a class="nav-link active" href="#info">Info</a>
          <a class="nav-link" href="#videos">Videos</a>
          <a class="nav-link" href="#stats">Statistics</a>
        </nav>
      </div>
    </div>
  </div>
</div>
<div class="profile-content">
  <div class="row player-info">
    <div class="container">
      <div class="row">
        <div class="col-md-3">
          <div class="player-avatar-card is-fixed-avatar">
            <div class="card-body">
              <div class="avatar-image">
                <img src="http://via.placeholder.com/350x150" alt="Profile Image" class="rounded-circle">
                <img class="flag rounded-circle" src="http://via.placeholder.com/32x32">
              </div>
              <h5>Name</h5>

              <div class="social-buttons">
                <div class="col-12">
                  <a class="btn btn-info btn-lg" href="#" role="button">
                    <i class="ion-plus-round"></i> follow</a>
                </div>
                <div class="col-12">
                  <a class="btn btn-info btn-outline-info" href="#" role="button">
                    <i class="ion-android-share-alt"></i> share</a>
                </div>
              </div>
            </div>
          </div>
        </div>
        <div class="col-md-9">
          <div id="info" class="player-info-card-content section-card">
            <div class="row">
              <div class="col-12">
                <h5><i class="ion-ios-list-outline title-icon"></i> Overview</h5>
                <hr class="info-title-hr">
              </div>
            </div>
            <div class="row info-content">
              <div class="col-12">
                <div class="row">
                  <div class="col-6 col-md-3 player-info-data">
                    <div class="row">
                      <div class="col-12 info-box">
                        <span class="info-label">Born</span>
                        <p>Born</p>
                      </div>
                    </div>
                  </div>
                  <div class="col-6 col-md-3 player-info-data">
                    <div class="row">
                      <div class="col-12 info-box">
                        <span class="info-label">Club</span>
                        <p>Club</p>
                      </div>
                    </div>
                  </div>
                  <div class="col-6 col-md-3 player-info-data">
                    <div class="row">
                      <div class="col-12 info-box">
                        <span class="info-label">Position</span>
                        <p>Position</p>
                      </div>
                    </div>
                  </div>
                  <div class="col-6 col-md-3 player-info-data">
                    <div class="row">
                      <div class="col-12 info-box">
                        <span class="info-label">Height</span>
                        <p>180 cm</p>
                      </div>
                    </div>
                  </div>
                  <div class="col-6 col-md-3 player-info-data">
                    <div class="row">
                      <div class="col-12 info-box">
                        <span class="info-label">Weight</span>
                        <p>75 kg</p>
                      </div>
                    </div>
                  </div>
                  <div class="col-6 col-md-3 player-info-data">
                    <div class="row">
                      <div class="col-12 info-box">
                        <span class="info-label">Foot</span>
                        <p>Both</p>
                      </div>
                    </div>
                  </div>
                  <div class="col-6 col-md-3 player-info-data">
                    <div class="row">
                      <div class="col-12 info-box">
                        <span class="info-label">Agent</span>
                        <p>Pro sports agency</p>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div class="section-card">
            <div id="videos" class="row">
              <div class="col-md-12">
                <h5 class="title-margin">
                  <i class="ion-ios-videocam-outline title-icon"></i> Videos
                </h5>
              </div>
            </div>
            <div class="row video-section">
              <div class="col-12">
                <div class="info-content">
                  <p></p>
                </div>
              </div>
            </div>
            <div class="col-md-6 col-lg-4 profile-video-box">
              <a href="">
                <div class="card bg-dark text-white">
                  <img src="http://via.placeholder.com/350x150" class="card-img" />
                  <div class="card-img-overlay">
                    <div class="play-icon-wrapper">
                      <i class="ion-ios-play"></i>
                    </div>
                    <div class="card-content">
                      <h5 class="card-title">title
                      </h5>
                      <p class="card-text">date
                      </p>
                    </div>
                  </div>
                </div>
              </a>
            </div>
          </div>

          <div class="section-card">
            <div id="stats" class="row">
              <div class="col-md-12">
                <h5 class="title-margin">
                  <i class="ion-ios-pulse-strong title-icon"></i> Performance data
                </h5>
              </div>
            </div>
            <div class="row">
              <div class="col-md-12">
                <div class="table-responsive">
                  <table class="table">
                    <thead>
                      <tr>
                        <th>
                          <div class="icon-wrapper">
                            <i class="ion-android-calendar"></i>
                          </div>
                          <span class="info-label">Season</span>
                        </th>
                        <th>
                          <div class="icon-wrapper">
                            <i class="flaticon-football-trophy-cup"></i>
                          </div>
                          <span class="info-label">Competition</span>
                        </th>
                        <th>
                          <div class="icon-wrapper">
                            <i class="flaticon-soccer-t-shirt"></i>
                          </div>
                          <span class="info-label">Club</span>
                        </th>
                        <th>
                          <div class="icon-wrapper">
                            <i class="ion-ios-football-outline"></i>
                          </div>
                          <span class="info-label">Goals</span>
                        </th>
                        <th>
                          <div class="icon-wrapper">
                            <i class="flaticon-football-strategic-sketch"></i>
                          </div>
                          <span class="info-label">Assists</span>
                        </th>
                        <th>
                          <div class="icon-wrapper yellow">
                            <i class="flaticon-football-yellow-warning-card"></i>
                          </div>
                          <span class="info-label">Yellow cards</span>
                        </th>
                        <th>
                          <div class="icon-wrapper red">
                            <i class="flaticon-football-card-with-cross-mark"></i>
                          </div>
                          <span class="info-label">Red cards</span>
                        </th>
                      </tr>
                    </thead>
                    <tbody>
                      <tr>
                        <td class="text-center">17/18</td>
                        <td class="text-center">NO</td>
                        <td class="text-center">Odd</td>
                        <td class="text-center">5</td>
                        <td class="text-center">3</td>
                        <td class="text-center">0</td>
                        <td class="text-center">0</td>
                      </tr>
                    </tbody>
                  </table>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>

There are three ways to achieve what you want.

Option 1

First, you can set the element you want fixed and the element that you want to scroll under it into a master element. Then set both of them to position: absolute and set overflow: scroll to the content element. In this example, the parent does not scroll, which is why the fixed element does not move.

CSS

.parent {
    position: relative;
    width: 800px;
    height: 400px;
    overflow: hidden; // Just to guarantee that no scroll appears
}
.fixed-menu {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 20px;
    z-index: 2;
}
.content {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    overflow-y: auto;
}

HTML

<div class="parent">
    <div class="fixed-menu"></div>
    <div class="content"></div>
</div>

Option 2

Similarly, you can create a child that is absolutely positioned, then create a grandchild that contains the fixed content. If you do not set the top/bottom/left/right of the fixed grandchild, it will remain fixed wherever the child sat.

.parent {
    position: relative;
    width: 25%;
    height: 200px;
    overflow: scroll;
    background-color: #f0f0f0;
}

.child {
    position: absolute;
    width: 50px; // Same size as the grandchild for easier positioning
    height: 50px;
    top: 50px;
    right: 50px;
}

.grandchild {
    width: 50px;
    height: 50px;
    position: fixed;
    background-color: red;
}

HTML

<div class="parent">
    Content...          
    <div class="child"><div class="grandchild"></div></div>
</div>

Option 3... Sort of

Third, you can create a set of local coordinates for children of an element by setting either will-change: transform or transform: translate*(0). This puts the element on its own render layer, and thus provides its own coordinates.

CSS

.parent {
    position: relative;
    width: 30%;
    height: 200px;
    overflow: scroll;
    background-color: #f0f0f0;
    transform: translateX(0); // I used X, but any will do.
}

.child {
    position: fixed;
    width: 50px;
    height: 50px;
    top: 25px;
    right: 25px;
    background-color: red;
}

HTML

<div class="parent">
    Content...      
    <div class="child"></div>
</div>

I'm unsure as to what has happened with this option. It previously worked in all browsers save for Internet Explorer, but now, in all modern browsers, the fixed element is simply acting like an absolute element in that it does not remain fixed, it instead will scroll with the content of the parent. I have done experiments and found that, by switching on and off CSS attributes on the parent in Chrome Dev Tools, that I can cause Chrome to glitch and render the child fixed to the parent. This is only a glitch, though, and it returns to rendering the first way after a refresh. Thus, I assume that this implementation decision is explicitly intentional.

Conclusion

You have two ways and the potential third way to achieve what you want. I'm still playing around with the third way since it does not follow what I remember, and the glitch that achieves what I want seems to indicate that the possibility is there, but for now it is just experiments.

Related