如何让非满高的position:fixed容器超出页面高度时可滚动
固定右上角通知组件内容溢出问题解决
我了解已有《Fixed Div Overflow is Off Screen》相关问题,但我的场景有所不同:我的DIV并非始终占满页面高度,因此bottom:0px方案不适用。我有一个固定在页面右上角的DIV,内部包含一个内容量可变的子DIV,当内容过多时,两个DIV会被撑开并超出页面边缘,且无法滚动。
原组件代码
JavaScript代码
// 函数内的普通文本为德语,适配我的德语网站 function nachrichtenwidgetAnzeigen() { const nw = document.createElement('div'); nw.id = 'nachrichtenwidget'; nw.hidden = true; nw.style = 'position:fixed;top:0px;right:0px;max-height:calc(100%-3px);max-width:33%;border-left:1px solid blue;border-bottom:1px solid blue;border-bottom-left-radius:6px;background-color:rgba(0,255,0,0.3);color:rgba(0,0,0,0);/*pointer-events:none;opacity:80%;*/'; nw.nachrichten = document.createElement('div'); nw.nachrichten.id = 'nachrichten'; nw.nachrichten.style = 'color:white;background-color:rgba(0,0,0,0);overflow-x: clip;overflow-y:auto;'; nw.nachrichten.addMsg = nw.addMsg = function(msg, iconURL=undefined, msgTimeout=10_000, options={color:'white',bgColor:'blue',onclickaction:''}) { // 设置msgTimeout=-1可创建永久消息 const msgElmnt = document.createElement('div'); try { if (typeof options.onclickaction === 'function') { msgElmnt.addEventListener('click', (e) => { msgElmnt.close(); options.onclickaction(); }); } else if (typeof options.onclickaction === 'string') { msgElmnt.addEventListener('click', (e) => { msgElmnt.close(); Function(options.onclickaction)(); }); } else { throw new TypeError(`options.onclickaction 类型错误,应为"function"或"string",当前类型为"${typeof options.onclickaction}"!`); } } catch (e) { console.warn('无法为消息绑定点击事件,忽略该设置'); console.warn(e); } if (iconURL!==undefined) { msgElmnt.msgImg = document.createElement('img'); msgElmnt.msgImg.style = 'max-width:33px;max-height:33px;padding-right:3px;'; msgElmnt.msgImg.src = iconURL; msgElmnt.appendChild(msgElmnt.msgImg); } else { msgElmnt.msgImg = undefined; } msgElmnt.innerHTML += msg; msgElmnt.id = `msg-${msg.replace(/[^a-z0-9]/gi, '-').toLowerCase()}`; msgElmnt.style = 'background-color:blue;color:white;padding:3px;margin:3px;border:0px solid blue;border-radius:3px;display:flex;flex-direction:row;'; if (msgTimeout >= 0) { msgElmnt.style.flexWrap = 'wrap'; // 仅当设置消息显示时长时,开启自动换行 } msgElmnt.timeout = document.createElement('div'); msgElmnt.timeout.style = 'width:100%;height:3px;border:0px solid blue;border-radius:3px;color:rgba(0,0,0,0);background-color:grey;flex:0 0 100%;'; msgElmnt.timeout.bar = document.createElement('div'); msgElmnt.timeout.bar.style = 'width:100%;height:3px;border:0px solid blue;border-radius:3px;color:rgba(0,0,0,0);background-color:lightblue;'; async function animTimeout(e) { msgElmnt.timeout.bar.animate([ { width: '100%' }, { width: '0%' } ], msgTimeout); msgElmnt.timeoutAnimation = msgElmnt.timeout.bar.getAnimations()[0]; msgElmnt.timeoutAnimation.addEventListener('finish', (e) => { msgElmnt.remove(); nw.countElmnt.innerText = nw.nachrichten.getElementsByTagName('div').length/3; }); // 动画结束后移除消息 } msgElmnt.addEventListener('mouseover', (e) => { if (msgElmnt.timeoutAnimation) { msgElmnt.timeoutAnimation.pause(); } msgElmnt.style.border = '1px solid white'; msgElmnt.style.padding = '2px'; }); msgElmnt.addEventListener('mouseout', (e) => { if (msgElmnt.timeoutAnimation) { msgElmnt.timeoutAnimation.play(); } msgElmnt.style.border = '0px solid blue'; msgElmnt.style.padding = '3px'; }); if (msgTimeout>=0) { msgElmnt.timeout.bar.addEventListener('click', animTimeout); } else { msgElmnt.timeout.hidden = true; } msgElmnt.close = function() { /* 添加模糊透明动画 */msgElmnt.remove(); nw.countElmnt.innerText = nw.nachrichten.getElementsByTagName('div').length/3; }; msgElmnt.timeout.appendChild(msgElmnt.timeout.bar); msgElmnt.timeout.bar.click(); msgElmnt.timeout.bar.removeEventListener('click', animTimeout); msgElmnt.appendChild(msgElmnt.timeout); nw.nachrichten.appendChild(msgElmnt); nw.countElmnt.innerText = nw.nachrichten.getElementsByTagName('div').length/3; // 除以3是因为每条消息包含1个外层DIV和2个嵌套DIV return msgElmnt; } const nwClose = document.createElement('button'); const nwOpen = document.createElement('button'); nwClose.id = 'nwClose'; nwClose.hidden = true; nwClose.innerText = '\xa0X\xa0'; // \xa0对应HTML实体 nwClose.title = '隐藏消息组件'; nwClose.style = 'background-color:red;border-radius:10px;'; nwClose.addEventListener('click', (e) => { nwClose.hidden = true; nw.hidden = true; nwOpen.hidden = false; }); nwOpen.id = 'nwOpen'; nwOpen.hidden = false; nwOpen.title = '显示消息组件'; nwOpen.style = 'position:fixed;top:0px;right:33px;background-color:green;'; nwOpen.addEventListener('click', (e) => { nwOpen.hidden = true; nw.hidden = false; nwClose.hidden = false; }); const nwTitle = document.createElement('span'); nwTitle.style = 'color:white;background-color:rgba(0,0,0,0);padding-left:3px;user-select:none;'; nwTitle.innerText = '站点消息'; nw.countElmnt = document.createElement('span'); nw.countElmnt.style = 'color:white;background-color:rgba(0,0,0,0);padding:3px;user-select:none;'; document.body.appendChild(nw); nwOpen.appendChild(nw.countElmnt); document.body.appendChild(nwOpen); nw.appendChild(nwClose); nw.appendChild(nwTitle); nw.appendChild(nw.nachrichten); nwOpen.click(); return nw; } // 生成组件: notifWidg = nachrichtenwidgetAnzeigen(); notifWidg.addMsg('这是一个通知组件,点击任意通知即可关闭它', 'https://www.lampe2020.de/favicon.ico', -1); // 生成测试消息,展示问题: setInterval(() => { notifWidg.addMsg('测试通知', undefined, 10_000) }, 1_000);
核心CSS逻辑(JS内联)
/* 主容器: div#nachrichtenwidget { position:fixed; top:0px; right:0px; max-width:33%; max-height: calc(100%-3px); ... } 内容容器: div#nachrichten { overflow-x:clip; overflow-y:auto; ... */
问题分析
- calc语法错误:
max-height: calc(100%-3px)缺少空格,浏览器无法正确解析该计算值,导致主容器高度不受限制,随内容无限撑开。 - 内容容器无高度约束:子容器
#nachrichten没有设置高度填充规则,即使主容器高度正确,子容器也会跟着内容溢出,无法触发滚动。
修复方案
修改两处关键样式:
- 主容器样式修改:
修复calc语法错误,同时添加flex布局,让子容器可以填充剩余空间:nw.style = 'position:fixed;top:0px;right:0px;max-height:calc(100% - 3px);max-width:33%;border-left:1px solid blue;border-bottom:1px solid blue;border-bottom-left-radius:6px;background-color:rgba(0,255,0,0.3);color:rgba(0,0,0,0);display:flex;flex-direction:column;'; - 内容容器样式修改:
添加flex:1,让容器填充主容器的剩余高度,触发滚动:nw.nachrichten.style = 'color:white;background-color:rgba(0,0,0,0);overflow-x: clip;overflow-y:auto;flex:1;';
效果对比
(右侧为期望效果,修复后可实现)
内容的提问来源于stack exchange,提问作者Lampe2020
相关产品推荐
相关产品推荐

