Skip to content

Commit 1cadad6

Browse files
Copilotruibaby
andcommitted
Fix page jitter by compensating for scrollbar width
Co-authored-by: ruibaby <[email protected]>
1 parent 93befea commit 1cadad6

File tree

4 files changed

+26
-92
lines changed

4 files changed

+26
-92
lines changed

README.md

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -64,36 +64,6 @@ halo:
6464

6565
其中,`pluginFinder.available('PluginSearchWidget')` 的作用是判断使用者是否安装和启用了此插件,如果没有安装或者没有启用,那么就不会显示搜索入口。
6666

67-
#### 配置选项
68-
69-
`SearchWidget.open()` 支持传入配置参数:
70-
71-
```javascript
72-
// 不传参数,使用默认配置
73-
SearchWidget.open();
74-
75-
// 传入搜索选项(旧版本兼容方式)
76-
SearchWidget.open({ keyword: '关键词' });
77-
78-
// 传入完整配置(推荐)
79-
SearchWidget.open({
80-
searchOptions: {
81-
keyword: '关键词',
82-
// 其他搜索选项...
83-
},
84-
lockScroll: false // 是否锁定页面滚动,默认为 true
85-
});
86-
```
87-
88-
**参数说明:**
89-
90-
- `searchOptions`: 搜索 API 的选项参数
91-
- `lockScroll`: 是否在打开搜索框时锁定页面滚动(隐藏滚动条),默认为 `true`
92-
- 设置为 `true` 时,打开搜索框会隐藏页面滚动条(默认行为)
93-
- 设置为 `false` 时,打开搜索框不会隐藏页面滚动条,可以避免页面抖动问题
94-
95-
**注意:** 如果你的网站在打开搜索框时出现页面抖动或内容偏移的问题,可以将 `lockScroll` 设置为 `false` 来解决。
96-
9767
### 自定义样式
9868

9969
虽然目前不能直接为搜索组件编写额外的样式,但可以通过一系列的 CSS 变量来自定义部分样式,开发者可以根据需求自行在主题中添加这些 CSS 变量,让搜索组件和主题更好地融合。

packages/search-widget/index.html

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -46,44 +46,30 @@
4646
</style>
4747
</head>
4848
<body>
49-
<h1>Search Widget Demo</h1>
50-
51-
<div>
52-
<button id="open-default">Open Modal (Default - Lock Scroll)</button>
53-
<button id="open-no-lock">Open Modal (No Lock Scroll)</button>
54-
<button id="color">Toggle Dark/Light Mode</button>
55-
</div>
49+
<h1>Search Widget - Page Jitter Fix Test</h1>
50+
<button>Open Search Modal</button>
51+
<button id="color">Toggle Dark/Light Mode</button>
5652

5753
<div style="margin-top: 2rem;">
58-
<h2>Configuration Examples</h2>
59-
<p>Default behavior (lockScroll = true): Page scrollbar is hidden when modal opens</p>
60-
<p>With lockScroll = false: Page scrollbar remains visible, preventing page jitter</p>
54+
<h2>Testing the Fix</h2>
55+
<p>This page has enough content to show a scrollbar. When you open the search modal, the page should NOT shift to the right.</p>
56+
<p>The fix works by calculating the scrollbar width and adding equivalent padding to compensate for the scrollbar removal.</p>
6157
</div>
6258

63-
<div style="margin-top: 2rem;">
64-
<h3>Long content to enable scrolling</h3>
65-
<div style="height: 2000px; background: linear-gradient(to bottom, #f0f0f0, #ffffff);">
66-
<p>Scroll down to see the scrollbar...</p>
67-
</div>
59+
<!-- Add enough content to ensure scrollbar appears -->
60+
<div style="height: 2000px; background: linear-gradient(to bottom, #f0f0f0, #e0e0e0);">
61+
<p style="padding: 2rem;">Long content to ensure scrollbar is visible...</p>
62+
<p style="padding: 2rem;">Notice that when the modal opens, there's no layout shift!</p>
6863
</div>
6964

7065
<search-modal></search-modal>
7166
</body>
7267
<script>
73-
const openDefaultBtn = document.getElementById('open-default');
74-
const openNoLockBtn = document.getElementById('open-no-lock');
68+
const button = document.querySelector('button');
7569
const searchModal = document.querySelector('search-modal');
7670

77-
// Open with default lockScroll (true)
78-
openDefaultBtn.addEventListener('click', () => {
79-
searchModal.lockScroll = true;
80-
searchModal.open = true;
81-
});
82-
83-
// Open with lockScroll = false
84-
openNoLockBtn.addEventListener('click', () => {
85-
searchModal.lockScroll = false;
86-
searchModal.open = true;
71+
button.addEventListener('click', () => {
72+
searchModal.open = !searchModal.open;
8773
});
8874

8975
const color = document.getElementById('color');

packages/search-widget/src/search-modal.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@ export class SearchModal extends LitElement {
1919
@property({ type: Object })
2020
options = {};
2121

22-
@property({ type: Boolean })
23-
lockScroll = true;
24-
2522
constructor() {
2623
super();
2724

@@ -45,12 +42,18 @@ export class SearchModal extends LitElement {
4542
return;
4643
}
4744

48-
if (this.lockScroll) {
49-
if (this.open) {
50-
document.body.style.overflow = 'hidden';
51-
} else {
52-
document.body.style.removeProperty('overflow');
45+
if (this.open) {
46+
// Calculate scrollbar width to prevent layout shift
47+
const scrollbarWidth =
48+
window.innerWidth - document.documentElement.clientWidth;
49+
document.body.style.overflow = 'hidden';
50+
// Add padding to compensate for scrollbar removal
51+
if (scrollbarWidth > 0) {
52+
document.body.style.paddingRight = `${scrollbarWidth}px`;
5353
}
54+
} else {
55+
document.body.style.removeProperty('overflow');
56+
document.body.style.removeProperty('padding-right');
5457
}
5558
}
5659

packages/widget/src/index.ts

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,7 @@ const searchModalElement = document.createElement(
1010

1111
document.body.append(searchModalElement);
1212

13-
export interface OpenOptions {
14-
/**
15-
* Search options for the search API
16-
*/
17-
searchOptions?: SearchOption;
18-
/**
19-
* Whether to lock the body scroll when modal is open
20-
* @default true
21-
*/
22-
lockScroll?: boolean;
23-
}
24-
25-
export function open(options?: SearchOption | OpenOptions) {
26-
// Handle backward compatibility
27-
if (options) {
28-
// Check if it's the new OpenOptions format
29-
if ('searchOptions' in options || 'lockScroll' in options) {
30-
const openOptions = options as OpenOptions;
31-
searchModalElement.options = openOptions.searchOptions || {};
32-
if (openOptions.lockScroll !== undefined) {
33-
searchModalElement.lockScroll = openOptions.lockScroll;
34-
}
35-
} else {
36-
// Legacy SearchOption format
37-
searchModalElement.options = options;
38-
}
39-
}
13+
export function open(options: SearchOption) {
14+
searchModalElement.options = options;
4015
searchModalElement.open = true;
4116
}

0 commit comments

Comments
 (0)