Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overflow scroll but visible

Tags:

html

css

I have a header element with an article element below it. The article has overflow: scroll. Please see my website here.

My goal is to make the header semi-transparent so that the article content will show behind it when scrolled. I want the article overflow to show with the header.

The main restriction is that the scrollbar should span from the bottom of the header, not the top.

How can such an effect be done?

like image 308
Randomblue Avatar asked May 23 '16 13:05

Randomblue


4 Answers

A trick is to copy the content. Below is a solution with a blurry and semi-transparent header.

$(function() {
  // Clone the content
  var $content = $('.content');
  var $clone = $('.clone').html($content.html());
  
  // Performance scrolling
  var content = $content.get(0);
  var clone = $clone.get(0);
  content.onscroll = function() {
    clone.scrollTop = content.scrollTop;
  };
});
div {
  width: 400px;
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  bottom: 0;
}

.content {
  top: 50px;
  overflow: scroll;
}

.clone {
  padding-top: 50px;
  overflow: hidden;
  -webkit-filter: blur(2px);
}

.header {
  height: 50px;
}

.overlay {
  background: rgba(240, 240, 240, 0.8);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="content">
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus at orci vestibulum, congue urna nec, fringilla dolor. Donec pellentesque odio non dui vehicula, eu gravida odio rhoncus. Sed eleifend eu nisi ullamcorper ultricies. Ut ante velit, facilisis
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus at orci vestibulum, congue urna nec, fringilla dolor. Donec pellentesque odio non dui vehicula, eu gravida odio rhoncus. Sed eleifend eu nisi ullamcorper ultricies. Ut ante velit, facilisis
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus at orci vestibulum, congue urna nec, fringilla dolor. Donec pellentesque odio non dui vehicula, eu gravida odio rhoncus. Sed eleifend eu nisi ullamcorper ultricies. Ut ante velit, facilisis
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus at orci vestibulum, congue urna nec, fringilla dolor. Donec pellentesque odio non dui vehicula, eu gravida odio rhoncus. Sed eleifend eu nisi ullamcorper ultricies. Ut ante velit, facilisis
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus at orci vestibulum, congue urna nec, fringilla dolor. Donec pellentesque odio non dui vehicula, eu gravida odio rhoncus. Sed eleifend eu nisi ullamcorper ultricies. Ut ante velit, facilisis
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus at orci vestibulum, congue urna nec, fringilla dolor. Donec pellentesque odio non dui vehicula, eu gravida odio rhoncus. Sed eleifend eu nisi ullamcorper ultricies. Ut ante velit, facilisis
</div>
<div class="header">
  <div class="clone"></div>
  <div class="overlay"></div>
</div>
like image 54
Randomblue Avatar answered Nov 15 '22 18:11

Randomblue


Scrollable elements will always clip inner content by their bounding box. Unless they add something like overflow: visible-scroll to the specs (I wish!).

There's a workaround for this particular case: a custom Webkit scrollbar (Webkit-only, of course). Simply style the "up" button such that its height and background color matches the header's. This will ensure the scroll bar's track does not extend underneath the header, while keeping styling consistent.

JSFiddle: "Webkit Scrollbar Hack For Translucent Headers"

header {
    background: rgba(240, 240, 240, 0.9);
    height: 60px;
}

::-webkit-scrollbar-button:start {
    background: rgba(240, 240, 240, 0.9);
    height: 60px;
}

Be sure to pad the top of your scrollable content area.

#content {
    padding-top: 60px;
}

As for the non-Webkit browsers, I can think of no CSS-only solutions.

like image 32
darrylyeo Avatar answered Nov 15 '22 20:11

darrylyeo


You could do this by adding padding to your content (that scrolls), the same padding as the height of the header. And then moving the content up and under the header (and making the header transparent). Then creating a custom scrollbar with some javascript and html/css that has an offset from the header.

like image 33
Nicklas Ridewing Avatar answered Nov 15 '22 19:11

Nicklas Ridewing


Update: Just 'scroll' events, no 'wheel' or 'mousewheel'.

CSS and JavaScript?

Here's a way: (jsfiddle).

Tested in Firefox 46 and Chrome 50.

This solution uses an empty dummy element inside a scrollable element, sized to match the height of the content-bearing element (with hidden scrollbar), and some lightweight JavaScript to relay 'scroll' events between content and dummy.

Pros:

  1. Uses browsers' native scrollbars and scroll events.
  2. No extra libraries needed
  3. Doesn't weigh down the DOM

Cons:

  1. It's a hack. But that's what we do!

HTML

<div id="wrapper">
  <div id="header"></div>
  <!-- An empty dummy to carry the scrollbar -->
  <div id="scroll-wrap">
    <div id="scroll-dummy"></div>
  </div>
  <!-- Content -->
  <div id="content-view">[Actual content.]</div>
</div>

CSS

body { overflow: hidden; }

#content-view {
  position: absolute;
  z-index: 0;
  top: 0; /* Place content behind header. */
  height: 100vh; /* Fill viewport. */
  overflow-y: scroll; /* Hidden scrollbar. */
}

#header {
  position: relative; /* Enable z-index. */
  z-index: 1; /* Place header above content. */
  height: 25vh; /* Top of viewport. */
}

#scroll-wrap {
  position: absolute; 
  z-index: 1; /* Place scrollbar above content. */  
  top: 25vh; /* Skip header. */
  height: 75vh; /* Fill remaining viewport. */
  right: 0; /* Avoid non-scroll mouse events. */
  overflow-y: scroll; /* Scrollbar! */  
}
#scroll-dummy { width: 1px; } /* Firefox won't scroll width:0 elements! */

JavaScript

var $ = document.getElementById.bind(document),
  contentView = $('content-view'), scrollDummy = $('scroll-dummy'),
  scrollWrap  = $('scroll-wrap'), wrapper = $('wrapper'), header=$('header');
  scrollWidth = scrollWrap.offsetWidth - scrollWrap.clientWidth;

// Hide content's actual scrollbar
contentView.style.right = -scrollWidth + 'px';

// Copy height of visible content to hidden dummy
function onContentChange() {
  window.requestAnimationFrame(function() {
    scrollDummy.style.height = contentView.scrollHeight - header.offsetHeight + 'px';
  });
}
window.addEventListener('resize', onContentChange);
onContentChange(); // Call whenever the contentView node changes!

// No event-triggering feedback loops    
var fromContent = false, fromScroll = false; 
// Update scrollbar scroll on content scroll
animate(contentView, 'scroll', function(e){
    if (fromScroll) fromScroll = false;
    else {
        fromContent = true;
        scrollWrap.scrollTop = contentView.scrollTop; // Scroll the scrollbar
    }
});
// Update content scroll on scrollbar scroll
animate(scrollWrap, 'scroll', function(){
    if (fromContent) fromContent=false;
    else {
      fromScroll = true;
      contentView.scrollTop = scrollWrap.scrollTop; // Scroll the content   
    }
});

// Wrap event handler with throttled rAF
function animate(element, event, func) {
  var lock = false;
  element.addEventListener(event, function(e) {
    if (!lock) {
      lock = true;
      window.requestAnimationFrame(function(){ func(e); lock = false; });
    }
  }, false);
}
like image 39
A. Vidor Avatar answered Nov 15 '22 18:11

A. Vidor