为任意 html 文档创建不显眼的覆盖
Creating unobtrusive overlay for arbitrary html document
我正在尝试创建一个叠加层,将其自身附加到现有 DOM 节点并覆盖其整个内容区域。无论此节点是页面的 body 还是某些深度嵌套的 div,这都应该有效。关键是我覆盖的页面布局不应该改变。最终,我的代码将 运行 作为现有 html 页面之上的浏览器扩展。
在非常简单的情况下,我遇到了一个问题,我试图用直接嵌套在文档 body 中的文本(或任何需要 space 的内容)覆盖页面。我别无选择,只能将叠加层 div 附加为 body 的另一个 child 节点,并将其位置设置为绝对位置并将其 width/height 设置为 100%。当然,在 body 静态定位(默认)的情况下,我的 div 将根据视口调整大小,而不是 body 的内容。如果内容溢出,我的叠加层将无法覆盖所有内容:\.
所有其他答案都建议设置 parent div 的位置(在我的例子中是 body )以将其定义为定位上下文。但是,我不能这样做。例如,将文档 body 的位置更改为 'relative',可能会更改 body 内容的布局,并破坏了不显眼的叠加层的目的。怎么办?
Extension-specific 欢迎提出建议。作为参考,扩展名为 Chrome.
这是一个 jsfiddle,其中包含一个我必须覆盖的假设页面。请注意,虽然原始页面格式很奇怪,但我的叠加层无法更改它。
<body>
<style>
.overlay {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%
/*some magic I am unaware of*/
}
</style>
<!-- begin original document (stupid hypothetical scenario) -->
<div style="position:absolute;top:0px;width:100%;height:100%;background-color:red;">
<!-- this div is part of the original html document I want to overlay.
It should behave as it did originally, i.e size to the viewport of the document-->
</div>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id tellus vehicula, tincidunt est fermentum, hendrerit dui. Nullam lacinia, justo sed porta hendrerit, nisl quam blandit nunc, ut imperdiet nibh metus in ante. Pellentesque viverra egestas
nulla eu dictum. Aliquam ac accumsan leo. Integer ut tellus odio. Duis blandit venenatis venenatis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum vel lorem egestas, tincidunt sem vel, venenatis
ipsum. Donec vitae blandit nibh. Curabitur cursus nunc arcu, id tempor massa gravida ut. Integer vulputate libero in placerat vestibulum. Duis quis turpis vel lectus venenatis rhoncus. Sed congue est consequat, dapibus odio sit amet, sollicitudin arcu.
Praesent hendrerit massa velit, vel pretium erat viverra quis. Proin non enim facilisis, venenatis dolor ut, dapibus nulla. Morbi vestibulum mollis felis ut venenatis. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus
mus. Ut mollis velit nulla, et tristique sapien auctor eu. Phasellus tincidunt mauris elit, vel fringilla leo consectetur a. Vivamus a porta magna. Mauris hendrerit leo eget sapien aliquet dignissim. Nunc id sem est. Integer sed lacus est. Nulla sit
amet sapien et ex aliquam malesuada quis vel eros. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus turpis ligula, elementum sit amet sapien nec, malesuada fringilla nibh. Duis euismod, purus semper viverra aliquam, ligula sem
vehicula mi, sit amet cursus mauris augue vel enim. Donec lacinia diam quis sapien laoreet vulputate in eu est. Proin consequat, ex vitae molestie pellentesque, libero purus pellentesque arcu, id porttitor orci sem a lectus. Morbi mattis in metus quis
euismod. Nam arcu augue, imperdiet eu felis eu, rhoncus facilisis lectus. Nullam placerat, tortor non tincidunt tristique, purus magna cursus leo, vitae sagittis odio turpis sodales nisi. Nullam vehicula erat nisl, ac venenatis massa rutrum sed. Mauris
massa tortor, volutpat vel nisl a, consectetur molestie sapien. Quisque eu elit nulla. Praesent at eros vehicula, lobortis purus quis, efficitur velit. Donec eget faucibus nisl. Praesent pharetra mattis porta. Donec volutpat lacinia dui non maximus.
Vivamus eu sodales leo. Ut eu ipsum scelerisque, consectetur turpis condimentum, malesuada elit. Proin tincidunt mauris metus, eu tincidunt ex ultrices ut. Sed sollicitudin leo nunc, in pharetra ligula egestas ut. Etiam suscipit eget ligula ut convallis.
Ut tempus tellus id ultrices rutrum. Nam accumsan fermentum metus, tristique gravida eros ultricies eget. Integer tortor diam, posuere ut ornare quis, bibendum ut tellus. Maecenas imperdiet lacus vitae felis viverra, nec dignissim lacus volutpat. Curabitur
et elit vehicula ipsum luctus tempor et sed enim. Fusce ultrices eget ante nec consectetur. Donec commodo nunc eget diam tristique, at euismod nisl commodo. Fusce felis neque, vulputate ut tincidunt sed, commodo in risus. Quisque sed magna sodales tortor
condimentum aliquam. Phasellus mattis justo eget diam tincidunt luctus. Cras pharetra ultrices sem, sed sollicitudin purus feugiat sed. Vivamus vitae tempor velit.
<!-- end original document -->
<div class='overlay'>
<!-- this div is my overlay. It should size to the content of the document body, not the viewport. Careful setting the body's position to relative, the other div will change!-->
</div>
</body>
我不知道 jQuery 是否是一个选项,但我无法抗拒...这是您可以如何使用 jQuery 来设置叠加层的样式
var $thingToOverlay = $('#someDivOrWhatever'); // use $(document) for whole page
var $overlay = $('.overlay');
var getMaxZ = function($elements){
var z;
return Math.max.apply(null, $elements.map(function(){
return isNaN(z = parseInt($(this).css("z-index"), 10)) ? 0 : z;
}));
};
$overlay.css({
'position': 'absolute',
'box-sizing': 'border-box',
'background-color': 'red',
'height': $thingToOverlay.height(),
'width': $thingToOverlay.width(),
'top': $thingToOverlay.offset().top, // don't use this for whole page (document), just set to 0
'left': $thingToOverlay.offset().left, // ditto
'z-index': getMaxZ($overlay.siblings()) // assuming overlay is last on page, no need to +1
});
这显然需要一些逻辑,具体取决于叠加层是需要覆盖整个页面还是只覆盖一个 div,但是您明白了吗?
我认为你最好将一个元素附加到正文(除非你可以访问一些可用于扩展的更高堆叠元素)并简单地使用 element.getClientBoundingRect()
来获取位置和尺寸。
function applyStyle(element, styles) {
for (var key in styles) {
element.style[key] = styles[key];
}
}
var overlay = document.body.appendChild(document.createElement('div')),
indicator = overlay.appendChild(document.createElement('div'));
// apply the styles
applyStyle(overlay, {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
zIndex: 2147483647, // it doesn't get higher than this
pointerEvents: 'none'
});
applyStyle(indicator, {
position: 'absolute',
border: '1px dotted red',
backgroundColor: 'rgba(255,0,0,0.2)'
});
window.addEventListener('mouseover', function(event) {
var bound = event.target.getBoundingClientRect();
applyStyle(indicator, {
top: bound.top + 'px',
left: bound.left + 'px',
width: bound.width + 'px',
height: bound.height + 'px'
});
});
.foo {
position: absolute;
top: 30px;
left: 10px;
width: 300px;
border: 1px solid gold;
}
.bar {
position: relative;
width: 40%;
margin: 200px auto 0;
max-height: 10em;
overflow: hidden;
border: 1px solid green;
}
<div class=foo>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam ut nibh dapibus tellus varius tristique vitae id elit. Fusce vestibulum neque a scelerisque pellentesque. Vestibulum eu odio risus. Aliquam id tellus in mauris sollicitudin vestibulum. Aenean vestibulum et massa vel dapibus. Pellentesque eu lectus odio. Aliquam vitae fermentum mauris. Pellentesque feugiat sem vel dolor imperdiet tempor.
</div>
<div class=bar>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam ut nibh dapibus tellus varius tristique vitae id elit. Fusce vestibulum neque a scelerisque pellentesque. Vestibulum eu odio risus. Aliquam id tellus in mauris sollicitudin vestibulum. Aenean vestibulum et massa vel dapibus. Pellentesque eu lectus odio. Aliquam vitae fermentum mauris. Pellentesque feugiat sem vel dolor imperdiet tempor.
</div>
这里"trickery"的位涉及:
- 使用最大 z-index 组合 叠加元素是
<body>
中的最后一个元素使得它 几乎 不可能任何页面高于它
- 鲜为人知的
getBoundingClientRect
宝藏
pointer-events: none
css,从叠加元素中删除交互性(只需在指示器上添加 pointer-events: auto
即可重新启用)
由于您的目标是一种特定的浏览器和一种(长青的)现代浏览器,我认为您不应该使用 jQuery。你不需要它。
我正在尝试创建一个叠加层,将其自身附加到现有 DOM 节点并覆盖其整个内容区域。无论此节点是页面的 body 还是某些深度嵌套的 div,这都应该有效。关键是我覆盖的页面布局不应该改变。最终,我的代码将 运行 作为现有 html 页面之上的浏览器扩展。
在非常简单的情况下,我遇到了一个问题,我试图用直接嵌套在文档 body 中的文本(或任何需要 space 的内容)覆盖页面。我别无选择,只能将叠加层 div 附加为 body 的另一个 child 节点,并将其位置设置为绝对位置并将其 width/height 设置为 100%。当然,在 body 静态定位(默认)的情况下,我的 div 将根据视口调整大小,而不是 body 的内容。如果内容溢出,我的叠加层将无法覆盖所有内容:\.
所有其他答案都建议设置 parent div 的位置(在我的例子中是 body )以将其定义为定位上下文。但是,我不能这样做。例如,将文档 body 的位置更改为 'relative',可能会更改 body 内容的布局,并破坏了不显眼的叠加层的目的。怎么办?
Extension-specific 欢迎提出建议。作为参考,扩展名为 Chrome.
这是一个 jsfiddle,其中包含一个我必须覆盖的假设页面。请注意,虽然原始页面格式很奇怪,但我的叠加层无法更改它。
<body>
<style>
.overlay {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%
/*some magic I am unaware of*/
}
</style>
<!-- begin original document (stupid hypothetical scenario) -->
<div style="position:absolute;top:0px;width:100%;height:100%;background-color:red;">
<!-- this div is part of the original html document I want to overlay.
It should behave as it did originally, i.e size to the viewport of the document-->
</div>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id tellus vehicula, tincidunt est fermentum, hendrerit dui. Nullam lacinia, justo sed porta hendrerit, nisl quam blandit nunc, ut imperdiet nibh metus in ante. Pellentesque viverra egestas
nulla eu dictum. Aliquam ac accumsan leo. Integer ut tellus odio. Duis blandit venenatis venenatis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum vel lorem egestas, tincidunt sem vel, venenatis
ipsum. Donec vitae blandit nibh. Curabitur cursus nunc arcu, id tempor massa gravida ut. Integer vulputate libero in placerat vestibulum. Duis quis turpis vel lectus venenatis rhoncus. Sed congue est consequat, dapibus odio sit amet, sollicitudin arcu.
Praesent hendrerit massa velit, vel pretium erat viverra quis. Proin non enim facilisis, venenatis dolor ut, dapibus nulla. Morbi vestibulum mollis felis ut venenatis. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus
mus. Ut mollis velit nulla, et tristique sapien auctor eu. Phasellus tincidunt mauris elit, vel fringilla leo consectetur a. Vivamus a porta magna. Mauris hendrerit leo eget sapien aliquet dignissim. Nunc id sem est. Integer sed lacus est. Nulla sit
amet sapien et ex aliquam malesuada quis vel eros. Interdum et malesuada fames ac ante ipsum primis in faucibus. Phasellus turpis ligula, elementum sit amet sapien nec, malesuada fringilla nibh. Duis euismod, purus semper viverra aliquam, ligula sem
vehicula mi, sit amet cursus mauris augue vel enim. Donec lacinia diam quis sapien laoreet vulputate in eu est. Proin consequat, ex vitae molestie pellentesque, libero purus pellentesque arcu, id porttitor orci sem a lectus. Morbi mattis in metus quis
euismod. Nam arcu augue, imperdiet eu felis eu, rhoncus facilisis lectus. Nullam placerat, tortor non tincidunt tristique, purus magna cursus leo, vitae sagittis odio turpis sodales nisi. Nullam vehicula erat nisl, ac venenatis massa rutrum sed. Mauris
massa tortor, volutpat vel nisl a, consectetur molestie sapien. Quisque eu elit nulla. Praesent at eros vehicula, lobortis purus quis, efficitur velit. Donec eget faucibus nisl. Praesent pharetra mattis porta. Donec volutpat lacinia dui non maximus.
Vivamus eu sodales leo. Ut eu ipsum scelerisque, consectetur turpis condimentum, malesuada elit. Proin tincidunt mauris metus, eu tincidunt ex ultrices ut. Sed sollicitudin leo nunc, in pharetra ligula egestas ut. Etiam suscipit eget ligula ut convallis.
Ut tempus tellus id ultrices rutrum. Nam accumsan fermentum metus, tristique gravida eros ultricies eget. Integer tortor diam, posuere ut ornare quis, bibendum ut tellus. Maecenas imperdiet lacus vitae felis viverra, nec dignissim lacus volutpat. Curabitur
et elit vehicula ipsum luctus tempor et sed enim. Fusce ultrices eget ante nec consectetur. Donec commodo nunc eget diam tristique, at euismod nisl commodo. Fusce felis neque, vulputate ut tincidunt sed, commodo in risus. Quisque sed magna sodales tortor
condimentum aliquam. Phasellus mattis justo eget diam tincidunt luctus. Cras pharetra ultrices sem, sed sollicitudin purus feugiat sed. Vivamus vitae tempor velit.
<!-- end original document -->
<div class='overlay'>
<!-- this div is my overlay. It should size to the content of the document body, not the viewport. Careful setting the body's position to relative, the other div will change!-->
</div>
</body>
我不知道 jQuery 是否是一个选项,但我无法抗拒...这是您可以如何使用 jQuery 来设置叠加层的样式
var $thingToOverlay = $('#someDivOrWhatever'); // use $(document) for whole page
var $overlay = $('.overlay');
var getMaxZ = function($elements){
var z;
return Math.max.apply(null, $elements.map(function(){
return isNaN(z = parseInt($(this).css("z-index"), 10)) ? 0 : z;
}));
};
$overlay.css({
'position': 'absolute',
'box-sizing': 'border-box',
'background-color': 'red',
'height': $thingToOverlay.height(),
'width': $thingToOverlay.width(),
'top': $thingToOverlay.offset().top, // don't use this for whole page (document), just set to 0
'left': $thingToOverlay.offset().left, // ditto
'z-index': getMaxZ($overlay.siblings()) // assuming overlay is last on page, no need to +1
});
这显然需要一些逻辑,具体取决于叠加层是需要覆盖整个页面还是只覆盖一个 div,但是您明白了吗?
我认为你最好将一个元素附加到正文(除非你可以访问一些可用于扩展的更高堆叠元素)并简单地使用 element.getClientBoundingRect()
来获取位置和尺寸。
function applyStyle(element, styles) {
for (var key in styles) {
element.style[key] = styles[key];
}
}
var overlay = document.body.appendChild(document.createElement('div')),
indicator = overlay.appendChild(document.createElement('div'));
// apply the styles
applyStyle(overlay, {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
zIndex: 2147483647, // it doesn't get higher than this
pointerEvents: 'none'
});
applyStyle(indicator, {
position: 'absolute',
border: '1px dotted red',
backgroundColor: 'rgba(255,0,0,0.2)'
});
window.addEventListener('mouseover', function(event) {
var bound = event.target.getBoundingClientRect();
applyStyle(indicator, {
top: bound.top + 'px',
left: bound.left + 'px',
width: bound.width + 'px',
height: bound.height + 'px'
});
});
.foo {
position: absolute;
top: 30px;
left: 10px;
width: 300px;
border: 1px solid gold;
}
.bar {
position: relative;
width: 40%;
margin: 200px auto 0;
max-height: 10em;
overflow: hidden;
border: 1px solid green;
}
<div class=foo>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam ut nibh dapibus tellus varius tristique vitae id elit. Fusce vestibulum neque a scelerisque pellentesque. Vestibulum eu odio risus. Aliquam id tellus in mauris sollicitudin vestibulum. Aenean vestibulum et massa vel dapibus. Pellentesque eu lectus odio. Aliquam vitae fermentum mauris. Pellentesque feugiat sem vel dolor imperdiet tempor.
</div>
<div class=bar>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam ut nibh dapibus tellus varius tristique vitae id elit. Fusce vestibulum neque a scelerisque pellentesque. Vestibulum eu odio risus. Aliquam id tellus in mauris sollicitudin vestibulum. Aenean vestibulum et massa vel dapibus. Pellentesque eu lectus odio. Aliquam vitae fermentum mauris. Pellentesque feugiat sem vel dolor imperdiet tempor.
</div>
这里"trickery"的位涉及:
- 使用最大 z-index 组合 叠加元素是
<body>
中的最后一个元素使得它 几乎 不可能任何页面高于它 - 鲜为人知的
getBoundingClientRect
宝藏 pointer-events: none
css,从叠加元素中删除交互性(只需在指示器上添加pointer-events: auto
即可重新启用)
由于您的目标是一种特定的浏览器和一种(长青的)现代浏览器,我认为您不应该使用 jQuery。你不需要它。