Skip to content

Commit d4a09ae

Browse files
author
Tapio
committed
Add first version
1 parent ec451c6 commit d4a09ae

File tree

4 files changed

+291
-2
lines changed

4 files changed

+291
-2
lines changed

README.md

+30-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,30 @@
1-
# overflow-shadow
2-
Pure JavaScript library to indicate overflowing content by displaying a shadow on the content edge
1+
# `overflow-shadow`
2+
3+
Having long content overflowing a container on a web page can become a problem, especially when the user's environment does not show a scrollbar. `overflow-shadow` solves this by showing a shadow gradient along the edge of the container that is overflowing. The implementation is in pure JavaScript and is simple to use.
4+
5+
In the picture the linear gradient shadows can be seen on top and bottom of the content box:
6+
7+
<img src="example.png" />
8+
9+
## Usage
10+
11+
Add an attribute `overflow-shadow` to the appropriate containers on the page and make sure the script [`overflow-shadow.js`](overflow-shadow.js) is executed.
12+
13+
```html
14+
<div overflow-shadow>
15+
/* Long content */
16+
</div>
17+
```
18+
19+
The script appends the CSS styles and the necessary DOM elements automatically. Currently, there are no settings or customizations available.
20+
21+
## Demo
22+
23+
Links to pages with examples.
24+
25+
* Demo page – https://tapiocode.github.io/overflow-shadow/
26+
* CodePen – https://codepen.io/tapiocode/pen/NWLamZO
27+
28+
# License
29+
30+
MIT License

example.png

62.6 KB
Loading

index.html

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
<!--
2+
Copyright (c) 2023 tapiocode
3+
https://github.com/tapiocode
4+
MIT License
5+
-->
6+
<!DOCTYPE html>
7+
<html>
8+
<head>
9+
<meta charset="utf-8">
10+
<title>overflow-shadow demo</title>
11+
<style>
12+
/* Local styles for the demo */
13+
:root {
14+
--body-bg: #f5f5f7;
15+
--body-color: #1d1d1f;
16+
--outline-color: #dfdfdf;
17+
--surface-background: #fff;
18+
}
19+
body {
20+
font-family: Verdana, Geneva, Tahoma, sans-serif;
21+
color: var(--body-color);
22+
background-color: var(--body-bg);
23+
}
24+
p {
25+
line-height: 1.5;
26+
}
27+
.content-wrapper {
28+
padding: 0 1rem;
29+
margin: 10vh auto;
30+
}
31+
.content {
32+
min-width: 17rem;
33+
max-width: 50rem;
34+
margin: 0 auto;
35+
}
36+
37+
h2 {
38+
margin: 2.4rem 0 1rem;
39+
}
40+
section {
41+
background-color: var(--surface-background);
42+
border-radius: .4rem;
43+
box-shadow: 2px 4px 12px rgba(0,0,0,.08);
44+
height: 25rem;
45+
outline: 1px solid var(--outline-color);
46+
overflow: hidden;
47+
}
48+
section h3,
49+
.section-container {
50+
padding-left: 2.4rem;
51+
padding-right: 2.4rem;
52+
}
53+
section h3 {
54+
margin: 0;
55+
padding-top: .9rem;
56+
padding-bottom: .9rem;
57+
border-bottom: 1px solid var(--outline-color);
58+
}
59+
section h4 {
60+
margin-bottom: 0rem;
61+
}
62+
section p {
63+
margin-top: .3rem;
64+
}
65+
66+
.section-container {
67+
margin-top: 1.6rem;
68+
margin-bottom: 3rem;
69+
}
70+
71+
.flex-column {
72+
display: flex;
73+
flex-direction: column;
74+
height: 100%;
75+
}
76+
</style>
77+
</head>
78+
<body>
79+
<div class="content-wrapper">
80+
<div class="content">
81+
82+
<h2>HTML Content</h2>
83+
<section>
84+
<div class="flex-column">
85+
<h3>
86+
<code>&lt;section></code>: The Generic Section element
87+
</h3>
88+
<div style="flex: 1; height: 0;">
89+
<div overflow-shadow>
90+
<div class="section-container">
91+
<p>
92+
The <code>&lt;section></code> HTML element represents a generic standalone section of a document,
93+
which doesn't have a more specific semantic element to represent it. Sections should
94+
always have a heading, with very few exceptions.
95+
</p>
96+
<h4>Attributes</h4>
97+
<p>
98+
This element only includes the global attributes.
99+
</p>
100+
<h4>Usage Notes</h4>
101+
<p>
102+
As mentioned above, <code>&lt;section></code> is a generic sectioning element, and should only be
103+
used if there isn't a more specific element to represent it. As an example, a navigation menu
104+
should be wrapped in a <code>&lt;nav></code> element, but a list of search results or a map display
105+
and its controls don't have specific elements, and could be put inside a <code>&lt;section></code>.
106+
</p>
107+
<h4>Using a section without a heading</h4>
108+
<p>
109+
Circumstances where you might see <code>&lt;section></code> used without a heading are typically
110+
found in web application/UI sections rather than in traditional document structures. In a document,
111+
it doesn't really make any sense to have a separate section of content without a heading to
112+
describe its contents. Such headings are useful for all readers, but particularly useful for
113+
users of assistive technologies like screen readers, and they are also good for SEO.
114+
</p>
115+
</div>
116+
</div>
117+
</div>
118+
</div>
119+
</section>
120+
121+
<h2>Plain Text</h2>
122+
<section>
123+
<div overflow-shadow>
124+
Laborum magni nesciunt et dignissimos rerum sunt possimus. Molestiae enim amet ipsum dolorem magnam nihil. Et reiciendis qui odit omnis.
125+
126+
Perferendis eaque adipisci non. Aut est ut possimus eius repellendus voluptatem. Odio voluptatem ipsa accusantium. Repudiandae fugiat perspiciatis a soluta fugit facere commodi non. Magni incidunt consequatur magni veritatis inventore facere eos neque. Autem quia et porro.
127+
128+
Ducimus consequuntur eveniet magni. Odit illo illo harum. Possimus aspernatur est vitae accusamus aliquid ut eveniet. Officiis ipsam quisquam quas qui. Sequi ex ut provident dolorum eius nisi sit ut.
129+
130+
Sit similique non architecto debitis doloribus quia. Autem animi veritatis maxime numquam nemo. Ipsum quas eos deleniti optio autem corrupti consequatur quia. Sint non voluptatem corporis. Labore maxime dolores qui eaque et magnam quo fugiat.
131+
132+
Nisi asperiores ut rerum nihil voluptas minima nisi nesciunt. Voluptate ea rerum ut fugit accusantium repellendus aut nihil. Eum quo molestias eum.
133+
134+
Laborum magni nesciunt et dignissimos rerum sunt possimus. Molestiae enim amet ipsum dolorem magnam nihil. Et reiciendis qui odit omnis.
135+
136+
Perferendis eaque adipisci non. Aut est ut possimus eius repellendus voluptatem. Odio voluptatem ipsa accusantium. Repudiandae fugiat perspiciatis a soluta fugit facere commodi non. Magni incidunt consequatur magni veritatis inventore facere eos neque. Autem quia et porro.
137+
138+
Ducimus consequuntur eveniet magni. Odit illo illo harum. Possimus aspernatur est vitae accusamus aliquid ut eveniet. Officiis ipsam quisquam quas qui. Sequi ex ut provident dolorum eius nisi sit ut.
139+
140+
Sit similique non architecto debitis doloribus quia. Autem animi veritatis maxime numquam nemo. Ipsum quas eos deleniti optio autem corrupti consequatur quia. Sint non voluptatem corporis. Labore maxime dolores qui eaque et magnam quo fugiat.
141+
142+
Nisi asperiores ut rerum nihil voluptas minima nisi nesciunt. Voluptate ea rerum ut fugit accusantium repellendus aut nihil. Eum quo molestias eum.
143+
144+
Laborum magni nesciunt et dignissimos rerum sunt possimus. Molestiae enim amet ipsum dolorem magnam nihil. Et reiciendis qui odit omnis.
145+
146+
Perferendis eaque adipisci non. Aut est ut possimus eius repellendus voluptatem. Odio voluptatem ipsa accusantium. Repudiandae fugiat perspiciatis a soluta fugit facere commodi non. Magni incidunt consequatur magni veritatis inventore facere eos neque. Autem quia et porro.
147+
148+
Ducimus consequuntur eveniet magni. Odit illo illo harum. Possimus aspernatur est vitae accusamus aliquid ut eveniet. Officiis ipsam quisquam quas qui. Sequi ex ut provident dolorum eius nisi sit ut.
149+
150+
Sit similique non architecto debitis doloribus quia. Autem animi veritatis maxime numquam nemo. Ipsum quas eos deleniti optio autem corrupti consequatur quia. Sint non voluptatem corporis. Labore maxime dolores qui eaque et magnam quo fugiat.
151+
152+
Nisi asperiores ut rerum nihil voluptas minima nisi nesciunt. Voluptate ea rerum ut fugit accusantium repellendus aut nihil. Eum quo molestias eum.
153+
</div>
154+
</section>
155+
156+
<h2>Image</h2>
157+
<div overflow-shadow style="height: 200px">
158+
<img alt="" width="100%" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='50' height='50'%3E%3Cpath fill='%23C0C0C9' d='M25.1,0H50v50H0V0H25.1z M45.7,45.7V4.3H4.3v41.4H45.7z'/%3E%3Cpath fill='%23C0C0C9' d='M40.6,37.5c-10.4,0-20.8,0-31.2,0c2.1-4.1,4.1-8.3,6.2-12.4c2.1,2.1,4.1,4.1,6.2,6.3 c3.2-4.2,6.3-8.4,9.4-12.6C34.4,25,37.5,31.2,40.6,37.5z'/%3E%3Ccircle fill='%23C0C0C9' cx='18.8' cy='15.6' r='3.1'/%3E%3C/svg%3E" />
159+
</div>
160+
161+
</div>
162+
</div>
163+
<script src="overflow-shadow.js"></script>
164+
</body>
165+
</html>

overflow-shadow.js

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/**
2+
* Copyright (c) 2023 tapiocode
3+
* https://github.com/tapiocode
4+
* MIT License
5+
*/
6+
7+
(function() {
8+
9+
const SCRIPT_NAME = 'overflow-shadow';
10+
const TAG_SELECTOR = `[${SCRIPT_NAME}]`;
11+
const WRAPPER_NAME = `${SCRIPT_NAME}-content-wrapper`;
12+
const getEdgeName = (edge) => `${SCRIPT_NAME}-${edge}`;
13+
14+
function wrapElems(wrapper, elem) {
15+
const elems = elem.childNodes;
16+
while (elems.length) {
17+
wrapper.appendChild(elems[0]);
18+
}
19+
elem.appendChild(wrapper);
20+
}
21+
22+
function getEdgeElem(edge) {
23+
const elem = document.createElement('div');
24+
elem.innerHTML = `<!-- ${SCRIPT_NAME} observable element for ${edge} -->`;
25+
return elem;
26+
}
27+
28+
function setupIntersectObserver(root) {
29+
['top', 'bottom'].forEach((edge) => {
30+
const edgeElem = getEdgeElem(edge);
31+
root[edge === 'top' ? 'prepend' : 'append'](edgeElem);
32+
33+
const options = {
34+
root,
35+
rootMargin: '10px',
36+
threshold: 1.0,
37+
};
38+
const callback = (entries) => {
39+
entries.forEach((entry) => {
40+
root.parentNode.classList[entry.isIntersecting ? 'remove' : 'add'](getEdgeName(edge));
41+
});
42+
};
43+
const observer = new IntersectionObserver(callback, options);
44+
observer.observe(edgeElem);
45+
});
46+
}
47+
48+
function initializeElems() {
49+
const elems = document.querySelectorAll(TAG_SELECTOR);
50+
elems.forEach((elem) => {
51+
const wrapper = document.createElement('div');
52+
wrapper.setAttribute(WRAPPER_NAME, '');
53+
wrapElems(wrapper, elem);
54+
setupIntersectObserver(wrapper);
55+
});
56+
}
57+
58+
function injectCss() {
59+
const css = document.createElement('style');
60+
const styles = `
61+
${TAG_SELECTOR} {
62+
position: relative;
63+
height: 100%;
64+
}
65+
${TAG_SELECTOR}:before,
66+
${TAG_SELECTOR}:after {
67+
background: linear-gradient(180deg, rgba(29,29,31,0.5) 0%, rgba(29,29,31,0.15) 35%, rgba(29,29,31,0) 100%);
68+
opacity: 0;
69+
transition: opacity .2s ease-in-out;
70+
content: '';
71+
display: block;
72+
height: 1.4rem;
73+
position: absolute;
74+
width: 100%;
75+
}
76+
${TAG_SELECTOR}:after {
77+
background: linear-gradient(0deg, rgba(29,29,31,0.5) 0%, rgba(29,29,31,0.15) 35%, rgba(29,29,31,0) 100%);
78+
bottom: 0;
79+
}
80+
${TAG_SELECTOR}.${getEdgeName('top')}:before,
81+
${TAG_SELECTOR}.${getEdgeName('bottom')}:after {
82+
opacity: 1;
83+
}
84+
[${WRAPPER_NAME}] {
85+
overflow-y: auto;
86+
height: 100%;
87+
}
88+
`;
89+
css.appendChild(document.createTextNode(styles));
90+
document.head.appendChild(css);
91+
}
92+
93+
initializeElems();
94+
injectCss();
95+
96+
})();

0 commit comments

Comments
 (0)