Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallSome links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Use an ID selector by putting # immediately before the element’s exact id value: #demo. In JavaScript, pass that selector to document.querySelector(), or use the ID-specific document.getElementById('demo'). IDs are case-sensitive, should be unique in the document, and must be escaped when their value is not a valid CSS identifier.
The basic ID selector
An ID selector matches an element whose id attribute has the specified value. The hash is selector syntax; it is not part of the HTML attribute value.
<button id="save-button">Save</button>
#save-button {
border: 2px solid red;
background: white;
}
The selector must match the value exactly. #save-button does not match id="Save-Button" because ID matching is case-sensitive.
Combine an ID with another selector
Place a type selector or universal selector before the ID in a compound selector. This narrows the match without changing the ID requirement.
#1 Best Overall
p#summary {
font-size: 1.5rem;
}
section#settings {
padding: 1rem;
}
*#app {
min-height: 100vh;
}
In normal markup, the ID alone is preferable because it is clear and already specific. Add a type or class condition only when you genuinely need to distinguish elements.
Selecting an ID in JavaScript
querySelector()
document.querySelector() accepts any valid CSS selector and returns the first matching element, or null when there is no match.
const panel = document.querySelector('#settings');
if (panel) {
panel.hidden = false;
}
Because the argument is a CSS selector string, the leading # is required. A missing element is not an exception; it produces null, so check the result before reading properties or calling methods on it.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
getElementById()
document.getElementById() is the direct ID-specific alternative. Pass only the ID value, without a hash.
const panel = document.getElementById('settings');
if (panel) {
panel.hidden = false;
}
For a normal ID, getElementById('settings') and querySelector('#settings') identify the same element. The former communicates that you are looking up an ID; the latter is useful when the selector may later become more complex.
querySelectorAll()
document.querySelectorAll() returns a collection of every match. It is useful for auditing duplicate IDs or operating on a selector that intentionally matches more than one element.
Rank #2
const matches = document.querySelectorAll('#legacy-widget');
matches.forEach((element) => {
element.classList.add('found');
});
Do not use duplicate IDs as a normal design. An ID is intended to identify one element, and duplicates make CSS, scripts, fragment links and accessibility relationships ambiguous.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesCSS selector versus JavaScript lookup
| Question | ID selector in CSS | querySelector() |
getElementById() |
|---|---|---|---|
| Primary purpose | Style matching elements | Retrieve the first element matching any CSS selector | Retrieve an element by its ID value |
| Input | #id, optionally combined with other selectors |
A complete CSS selector string, such as #id |
The ID value only, such as id |
| No match | No rule is applied | Returns null |
Returns null |
| Multiple matches | Can match every element carrying that value | Returns the first match in depth-first document order | Designed for one ID; duplicate markup is invalid practice |
| Selector flexibility | Supports CSS selector combinations | Supports CSS selector combinations | ID lookup only |
IDs that contain numbers or punctuation
HTML permits ID values that are not valid CSS identifiers. An ID beginning with a number or containing punctuation can therefore work in markup but fail as an unescaped selector.
Escape a dynamic ID with CSS.escape()
When an ID comes from data, a URL, a database or user input, escape it before interpolating it into a selector.
const id = 'item:42';
const element = document.querySelector(`#${CSS.escape(id)}`);
if (element) {
element.scrollIntoView();
}
CSS.escape() protects punctuation, whitespace and leading characters that have special meaning in CSS. It also prevents malformed input from turning into a different selector. Do not concatenate an untrusted ID directly into querySelector().
Escaping a literal CSS rule
If the value is known when you write the stylesheet, escape the invalid character or leading digit in the selector.
/* id="item?one" */
#item\?one {
color: crimson;
}
/* id="123item" */
#\00003123item {
color: navy;
}
An invalid, unescaped selector is ignored by CSS. In JavaScript, passing an invalid selector to querySelector() throws a SyntaxError instead of returning null, so escaping is part of input validation.
Uniqueness, case and document scope
Keep IDs unique
Use each ID once per document. Duplicate values can cause a CSS rule to affect several elements, while querySelector() returns only the first one in document order. If you need a reusable hook for a group, use a class and select it with .class-name.
<article class="card">...</article>
<article class="card">...</article>
Match case exactly
<div id="Profile"></div>
/* Does not match: */
#profile { ... }
/* Matches: */
#Profile { ... }
Choose the correct document
document.getElementById() searches the document. If the element is inside a component’s shadow root, query that shadow root instead:
const host = document.querySelector('#widget-host');
const shadowPanel = host?.shadowRoot?.querySelector('#panel');
A selector run on the main document cannot see nodes encapsulated in a shadow root. Likewise, querying an element before its markup exists returns null; run the code after the relevant HTML has been parsed or after the component has rendered.
Recommended Free Tools
Reliable patterns for real code
Wait until the DOM exists
document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('signup-form');
if (!form) return;
form.addEventListener('submit', (event) => {
event.preventDefault();
});
});
Scripts placed at the end of <body>, or scripts marked defer, also run after the document has been parsed. Choose one loading strategy and still handle a missing element when templates can vary.
Use a selector when you need a relationship
const invalidEmail = document.querySelector(
'#signup-form input[name="email"].invalid'
);
This is where querySelector() earns its flexibility: it can combine an ID with descendants, attributes, classes and state selectors. Use getElementById() first when the ID alone is the complete requirement.
Do not confuse an ID with a fragment URL
A link such as <a href="#details"> navigates to the element whose ID is details. The same value can be used in CSS as #details, but the contexts are different: the URL uses a fragment, while CSS and querySelector() use selector syntax.
Rank #4
Troubleshooting checklist
- No style appears: verify that the HTML says
id="...", the stylesheet uses#..., spelling and case match, and the stylesheet is loaded. querySelector()returnsnull: confirm the code runs after the element is created, that you included the hash, and that the selector is scoped to the correct document or shadow root.getElementById()returnsnull: pass the raw ID without#; for example, usegetElementById('demo'), notgetElementById('#demo').querySelector()throwsSyntaxError: the selector is invalid, often because an ID contains punctuation or starts with a digit. Build it withCSS.escape().- The wrong element is changed: inspect the document for duplicate IDs.
querySelector()deliberately returns the first match. - A rule seems ignored: inspect the selector in developer tools. An unescaped invalid ID selector is discarded by the CSS parser; also check whether another rule wins through the cascade.
- A dynamic component is missed: query after rendering, or use event delegation on a stable ancestor when elements are inserted later.
Performance and maintainability
For one known ID, getElementById() states intent directly. querySelector() is the better fit when you already have a compound selector or need to change the condition without rewriting the lookup API. There is no meaningful universal speed difference, so choose based on clarity and selector requirements rather than an assumed benchmark.
Cache a reference when the same element is used repeatedly, avoid querying in tight loops when a single lookup will do, and keep IDs stable when they are part of JavaScript, CSS, tests or deep links. Use classes for repeated styling and data attributes for behavior hooks when uniqueness is not required.
Or skip the browser setup
If your goal is to capture a page or a selected element rather than manipulate it in your own browser code, ScreenshotNeo provides a website screenshot API and MCP server. It can capture a full page or one CSS-selected element, load lazy images, apply custom CSS or JavaScript, wait for a selector, and return PNG, JPEG, WebP or PDF. Before capture it accepts consent banners and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be disabled.
Use a GET request (see the ScreenshotNeo API documentation):
curl -G "https://api.screenshotneo.com/v1/shot"
-d access_key=YOUR_API_KEY
--data-urlencode url=https://example.com
-o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Only clean shots are billed. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and response headers report the page verdict and whether it was billed (X-Page-Verdict and X-Billed). An MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.
The Free plan includes 1,000 shots per month without a card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan, and yearly billing provides two months free. Create a free ScreenshotNeo account to try it with no card.
Quick Recap
Practical decision guide
- Choose a CSS
#idrule when you are styling one uniquely identified element. - Choose
getElementById()when JavaScript needs one known ID. - Choose
querySelector()when you need a compound CSS selector. - Choose
querySelectorAll()only when multiple matches are intentional or you are diagnosing duplicate IDs. - Escape every dynamic ID with
CSS.escape()before constructing a selector. - Fix duplicate IDs and timing problems instead of compensating with increasingly complex selectors.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

