oglasi: brez praznega prostora okrog kreative

AdSense odzivni enoti vnaprej doloci visino po sirini zaslona. Ce je
postrezena kreativa nizja, ostane pod njo prazen rezerviran pas znotraj
okvirja - to je bilo vidno na clanku pod DonCarlos oglasom.

- AdSense komponenta po zapolnitvi poravna visino <ins> na dejansko visino
  oglasnega okvirja (ob 0/300/1000/2500 ms, ob vsaki spremembi DOM enote in
  ob resize). Nic se ne odreze, visina je natanko taksna kot oglas.
  MutationObserver zdaj tece tudi pri enotah brez onAdStatus.
- InArticleAd: odstranjen minHeight 260 px, ki je rezerviral prostor tudi ce
  je bila kreativa nizja.
- MultiplexAd: odstranjen min-h-[250px] iz istega razloga.
This commit is contained in:
Claude
2026-08-28 09:47:04 +00:00
parent 907e63d3d2
commit 43eff55ba3
+28 -4
View File
@@ -44,11 +44,30 @@ export default function AdSense({
// Google postavi data-ad-status na "filled", "unfilled" ali "unfill-optimized".
// Ce statusa ni, se zanesemo na dejansko visino. Odlocimo se enkrat.
// AdSense odzivni enoti vnaprej doloci visino po sirini zaslona. Ce je
// postrezena kreativa nizja, ostane pod njo prazen rezerviran pas znotraj
// okvirja. Visino <ins> zato poravnamo na dejansko visino oglasnega okvirja.
// Nic se ne odreze - visina je natanko taksna kot oglas.
let fitTimers: ReturnType<typeof setTimeout>[] = [];
const fitToCreative = () => {
const f = ins?.querySelector("iframe") as HTMLIFrameElement | null;
if (!ins || !f) return;
const h = f.getBoundingClientRect().height;
if (h > 10 && Math.abs(ins.getBoundingClientRect().height - h) > 2) {
ins.style.height = `${Math.ceil(h)}px`;
}
};
const scheduleFit = () => {
fitTimers.forEach(clearTimeout);
fitTimers = [0, 300, 1000, 2500].map((d) => setTimeout(fitToCreative, d));
};
const decide = (filled: boolean) => {
if (decided) return;
decided = true;
obs?.disconnect();
if (timer) clearTimeout(timer);
if (filled) scheduleFit();
onAdStatus?.(filled);
};
// Visina samega <ins> ni dokaz - nekatere enote imajo rezerviran prostor.
@@ -76,11 +95,15 @@ export default function AdSense({
pushed.current = true;
} catch (e) {
}
if (!onAdStatus || !ins) return;
obs = new MutationObserver(check);
if (!ins) return;
// Opazujemo tudi pri enotah brez onAdStatus - potrebujemo jih za poravnavo
// visine na kreativo.
obs = new MutationObserver(() => { check(); fitToCreative(); });
obs.observe(ins, { attributes: true, childList: true, subtree: true, attributeFilter: ["data-ad-status", "style"] });
timer = setTimeout(() => decide(hasFrame()), 3000);
window.addEventListener("resize", scheduleFit);
check();
scheduleFit();
};
if (eager || !ins || typeof IntersectionObserver === "undefined") {
@@ -100,6 +123,8 @@ export default function AdSense({
io?.disconnect();
obs?.disconnect();
if (timer) clearTimeout(timer);
fitTimers.forEach(clearTimeout);
window.removeEventListener("resize", scheduleFit);
};
}, []);
@@ -204,7 +229,6 @@ export function InArticleAd() {
return (
<div
className={shown ? "my-6 rounded-md overflow-hidden bg-card border border-card-border" : ""}
style={shown ? { minHeight: "260px" } : undefined}
>
{shown && (
<div className="text-[9px] text-muted-foreground/40 text-center pt-1 uppercase tracking-widest">Anzeige</div>
@@ -230,7 +254,7 @@ export function MultiplexAd() {
slot="4593001335"
format="autorelaxed"
style={{ display: "block" }}
className={shown ? "w-full min-h-[250px]" : "w-full"}
className="w-full"
onAdStatus={setFilled}
/>
</div>