Cafés, brunchs & glaciers à Santa Pola

Pour un café con leche le matin ou une glace après la plage, Santa Pola compte 27 cafés, salons et glaciers. De quoi caler chaque pause de la journée.

Cafe Fleur by Maison Rêve

★ 4.8

À Gran Alacant, Café Fleur (Maison Rêve) soigne le petit-déjeuner et la pause café dans un cadre coquet. Cafés, douceurs et brunchs à savourer le matin ou en milieu de journée, pour démarrer la journée en douceur ou faire une halte entre deux courses.

Voir sur la carte →

Heladería El Sueño

À Santa Pola, l'Heladería El Sueño allie glaces artisanales et cocktails maison pour une pause gourmande au bord de la mer. Parfums classiques, coupes généreuses et boissons fraîches s'y dégustent en terrasse ou à emporter, entre deux baignades ou en fin de journée. Une adresse sucrée et rafraîchissante pour faire une halte quand il fait chaud.

Voir sur la carte →

Luis Baldó Heladería-Horchatería

★ 4.4

Glaces artisanales et horchata, la boisson valencienne à base de souchet : chez Luis Baldó, on goûte une tradition rafraîchissante très ancrée dans la région. Une halte gourmande à Santa Pola, à savourer en terrasse après la plage ou en fin de journée, parfum classique ou granité bien frais.

Voir sur la carte →

Jijonenca Gran Playa

★ 4.0

Face à la Gran Playa, Jijonenca prolonge la tradition glacière de Xixona : glaces artisanales et horchata bien fraîche. La halte douceur après la baignade, à emporter sur le sable ou à savourer en terrasse quand le soleil tape.

Voir sur la carte →

Consultez aussi notre guide interactif complet de Santa Pola.

Choisir la langue
🇫🇷
Français
Santa Pola. Découverte.
🇪🇸
Español
Santa Pola. Descubierta.
🇬🇧
English
Santa Pola. Explored.
(function () { if (window === window.top) return; const allowedParentOrigins = ["https://www.perplexity.ai","https://perplexity.ai","https://testing.perplexity.ai","https://staging.perplexity.ai","https://*.preview.i.perplexity.ai","http://localhost:3000","http://127.0.0.1:3000","http://localhost:5173","http://127.0.0.1:5173"]; const MAX_FONT_BYTES = 500 * 1024; const MAX_TOTAL_FONT_BYTES = 2 * 1024 * 1024; let scrollForwarding = false; let scrollRaf = 0; let trustedTopOrigin = null; // Allow entries like "https://*.preview.i.perplexity.ai" — the wildcard // matches a single DNS label (no dots), so "https://*.foo" cannot stretch // across multiple labels. function matchesAllowedOrigin(origin) { if (!origin) return false; for (const entry of allowedParentOrigins) { if (!entry.includes("*")) { if (entry === origin) return true; continue; } const pattern = new RegExp( "^" + entry.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "[^.]+") + "$", ); if (pattern.test(origin)) return true; } return false; } // Trust decision: when the sender is same-origin-visible (event.origin is a // real origin like https://www.perplexity.ai) we trust event.origin directly. // When event.origin is "null" (opaque broker srcdoc), we fall back to the // broker's stamped `parentOrigin` to identify the top window. The fallback // is claim-only — we rely on the browser's native `targetOrigin` enforcement // on the response path (see postToTrustedTop) to ensure replies can't be // delivered to anyone but the actual top window of that claimed origin. function getTrustedParentOrigin(event) { const forwardedParentOrigin = typeof event.data.parentOrigin === "string" ? event.data.parentOrigin : null; const parentOrigin = event.origin === "null" ? forwardedParentOrigin : event.origin; return matchesAllowedOrigin(parentOrigin) ? parentOrigin : null; } // All responses go to window.top with targetOrigin = the allowlisted origin. // An attacker that iframes us inside their own null-origin broker can claim // any parentOrigin they like, but the browser will drop the reply whenever // the real top's origin doesn't match — so the screenshot never leaves. function postToTrustedTop(message) { if (!trustedTopOrigin) return; try { window.top.postMessage(message, trustedTopOrigin); } catch (_error) {} } function inlineAll(original, clone) { if (original.nodeType !== 1 || clone.nodeType !== 1) return; try { const computedStyle = getComputedStyle(original); // cssText on a computed style is the serialized declaration in modern // Chromium/Safari — a single read beats enumerating ~400 longhand // properties. Firefox returns "" here, so we fall back on empty. const serialized = computedStyle.cssText; if (serialized) { clone.style.cssText = serialized; } else { const parts = new Array(computedStyle.length); for (let index = 0; index < computedStyle.length; index += 1) { const property = computedStyle[index]; parts[index] = `${property}:${computedStyle.getPropertyValue(property)};`; } clone.style.cssText = parts.join(""); } } catch (_error) {} const originalChildren = original.children; const clonedChildren = clone.children; for ( let index = 0; index < originalChildren.length && index < clonedChildren.length; index += 1 ) { inlineAll(originalChildren[index], clonedChildren[index]); } } function extractFontUrl(srcValue) { const matches = [ ...srcValue.matchAll( /url\(["']?([^"')]+)["']?\)(?:\s*format\(["']?([^"')]+)["']?\))?/gi, ), ]; if (matches.length === 0) return null; const woff2 = matches.find((m) => m[2] && m[2].toLowerCase().includes("woff2")); if (woff2) return woff2[1]; const woff = matches.find((m) => m[2] && m[2].toLowerCase().includes("woff")); if (woff) return woff[1]; return matches[0][1]; } // Cache resolved font URL -> data URI across captures. Fonts on a page // essentially never change, and a batch run emits multiple captures back to // back — without this we'd refetch + re-base64 every time. const fontDataUriCache = new Map(); const SRC_DECLARATION_RE = /src\s*:\s*[^;}]+/i; async function fetchAsDataUri(url) { if (fontDataUriCache.has(url)) return fontDataUriCache.get(url); let dataUri = null; try { const response = await fetch(url, { mode: "cors", credentials: "omit" }); if (response.ok) { const blob = await response.blob(); if (blob.size <= MAX_FONT_BYTES) { dataUri = await new Promise((resolve) => { const reader = new FileReader(); reader.onloadend = () => resolve(typeof reader.result === "string" ? reader.result : null); reader.onerror = () => resolve(null); reader.readAsDataURL(blob); }); } } } catch (_error) { dataUri = null; } fontDataUriCache.set(url, dataUri); return dataUri; } function collectFontFaceRuleTexts() { const rules = []; for (const sheet of document.styleSheets) { let cssRules; try { cssRules = sheet.cssRules; } catch (_error) { continue; } if (!cssRules) continue; for (const rule of cssRules) { const cssText = rule.cssText || ""; if (cssText.startsWith("@font-face")) rules.push(cssText); } } return rules; } async function buildInlinedFontCss() { const ruleTexts = collectFontFaceRuleTexts(); if (ruleTexts.length === 0) return null; const resolved = ruleTexts.map((cssText) => { if (!SRC_DECLARATION_RE.test(cssText)) return null; const srcMatch = cssText.match(/src\s*:\s*([^;}]+)[;}]/i); if (!srcMatch) return null; const url = extractFontUrl(srcMatch[1]); if (!url) return null; try { return { cssText, url: new URL(url, document.baseURI).href }; } catch (_error) { return null; } }); const dataUris = await Promise.all( resolved.map((entry) => (entry ? fetchAsDataUri(entry.url) : Promise.resolve(null))), ); const inlined = []; let totalBytes = 0; for (let index = 0; index < resolved.length; index += 1) { const entry = resolved[index]; const dataUri = dataUris[index]; if (!entry || !dataUri) continue; const approxBytes = dataUri.length * 0.75; if (totalBytes + approxBytes > MAX_TOTAL_FONT_BYTES) break; totalBytes += approxBytes; inlined.push(entry.cssText.replace(SRC_DECLARATION_RE, `src: url("${dataUri}")`)); } return inlined.length > 0 ? inlined.join("\n") : null; } function stripExternal(clone) { const images = clone.querySelectorAll("img"); for (let index = 0; index < images.length; index += 1) { const src = images[index].getAttribute("src"); if (src && !src.startsWith("data:")) images[index].removeAttribute("src"); } const elements = clone.querySelectorAll("*"); for (let index = 0; index < elements.length; index += 1) { const style = elements[index].style.cssText; if (style && style.includes("url(")) { elements[index].style.cssText = style.replace( /url\(["']?(?!data:)[^)"']*["']?\)/gi, "none", ); } } } function emitScroll() { scrollRaf = 0; if (!scrollForwarding) return; postToTrustedTop({ type: "INLINE_EDIT_SCROLL", scrollX: window.scrollX, scrollY: window.scrollY, }); } window.addEventListener( "scroll", function () { if (!scrollForwarding || scrollRaf) return; scrollRaf = requestAnimationFrame(emitScroll); }, { passive: true, capture: true }, ); async function handleCaptureRequest(event) { const requestId = event.data.requestId; const scrollX = window.scrollX; const scrollY = window.scrollY; const width = window.innerWidth; const height = window.innerHeight; function postResult(dataUrl) { postToTrustedTop({ type: "INLINE_EDIT_SCREENSHOT_RESULT", requestId, dataUrl, scrollX, scrollY, }); } try { // Wait for any pending web fonts to resolve so both inline metrics and // the @font-face inlining below see the same loaded faces. if (document.fonts && document.fonts.ready) { try { await document.fonts.ready; } catch (_error) {} } const clone = document.documentElement.cloneNode(true); inlineAll(document.documentElement, clone); const removedNodes = clone.querySelectorAll("script,link[rel=\"stylesheet\"],style"); for (let index = 0; index < removedNodes.length; index += 1) { removedNodes[index].remove(); } stripExternal(clone); // Re-embed web fonts as data-URI @font-face rules so the SVG rasterizer // can resolve them — external font URLs aren't fetched during // foreignObject rendering, which would otherwise force a fallback face // and change text metrics. const inlinedFontCss = await buildInlinedFontCss(); if (inlinedFontCss) { const styleEl = document.createElement("style"); styleEl.textContent = inlinedFontCss; const head = clone.querySelector("head"); if (head) head.appendChild(styleEl); else clone.insertBefore(styleEl, clone.firstChild); } const html = new XMLSerializer().serializeToString(clone); const svg = `` + '' + `
` + `
` + html + "
"; const svgUrl = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`; const image = new Image(); image.onload = function () { const canvas = document.createElement("canvas"); canvas.width = width; canvas.height = height; canvas.getContext("2d").drawImage(image, 0, 0); postResult(canvas.toDataURL("image/png")); }; image.onerror = function () { postResult(null); }; image.src = svgUrl; } catch (_error) { postResult(null); } } window.addEventListener("message", function (event) { if (!event.data) return; // Only accept messages from the direct parent frame. Blocks sibling / // unrelated-window postMessage senders that could otherwise reach us. if (event.source !== window.parent) return; const trustedParentOrigin = getTrustedParentOrigin(event); if (!trustedParentOrigin) return; trustedTopOrigin = trustedParentOrigin; if (event.data.type === "INLINE_EDIT_SCROLL_START") { scrollForwarding = true; emitScroll(); return; } if (event.data.type === "INLINE_EDIT_SCROLL_STOP") { scrollForwarding = false; if (scrollRaf) cancelAnimationFrame(scrollRaf); scrollRaf = 0; return; } if (event.data.type !== "INLINE_EDIT_CAPTURE_REQUEST") return; handleCaptureRequest(event); }); })();