-
What's new in Safari and WebKit
Explore the latest features in Safari and WebKit and learn how you can make better and more powerful websites. We'll take you on a tour through the latest updates to HTML, CSS enhancements, Web Inspector tooling, Web APIs, and more.
Recursos
- Safari Technology Preview
- Safari Release Notes
- WebKit Open Source Project
- Learn more about bug reporting
- MDN Web Docs - Web Extensions API
Vídeos relacionados
WWDC23
- Explore media formats for the web
- What’s new in CSS
- What’s new in web apps
- What’s new in Web Inspector
WWDC22
-
Buscar neste vídeo...
-
-
2:59 - Dialog element
<!-- <dialog> element --> <dialog method="dialog"> <form id="dialogForm"> <label for="givenName">Given name:</label> <input class="focus" type="text" name="givenName"> <label for="familyName">Family name:</label> <input class="focus" type="text" name="familyName"> <label> <input type="checkbox"> Can trade in person </label> <button>Send</button> </form> </dialog> -
3:09 - Backdrop pseudo-class
/* ::backdrop pseudo-element */ dialog::backdrop { background: linear-gradient(rgba(233, 182, 76, 0.7), rgba(103, 12, 0, 0.6)); animation: fade-in 0.5s; } @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } -
3:53 - inert attribute
// inert attribute function switchToIndex(index) { this.items.forEach(item => item.inert = true); this.items[index].inert = false; this.currentIndex = index; } -
4:22 - Lazy image loading
<img src="images/shirt.jpg" loading="lazy" alt="a brown polo shirt" width="500" height="600"> -
6:46 - Container Queries
/* Container queries */ .container { container-type: inline-size; container-name: clothing-card; } .content { display: grid; grid-template-rows: 1fr; gap: 1rem; } @container clothing-card (width > 250px) { .content { grid-template-columns: 1fr 1fr; } /* additional layout code */ } -
8:05 - Cascade layers
/* Author Styles - Layer A */ @layer utilities { div { background-color: red; } } /* Author Styles - Layer B */ @layer customizations { div { background-color: teal; } } /* Author Styles - Layer C */ @layer userDefaults { div { background-color: yellow; } } -
8:54 - :has() pseudo-class
<!-- :has() pseudo-class --> <style> form:has(input[type="checkbox"]:checked) { background: #ff927a; } </style> <form class="message"> <textarea rows="5" cols="60" name="text" placeholder="Enter text"></textarea> <div class="checkbox"> <input type="checkbox" value="urgent"> <label>Urgent?</label> </div> <button>Send Message</button> </form> -
11:08 - Offset Path
/* offset-path */ :is(.blue, .teal, .yellow, .red) { offset-path: circle(9vw at 5vw 50%); } @keyframes move { 100% { offset-distance: 100%; } } /* Animation */ .clothing-header.clicked :is(.blue, .teal, .red, .yellow) { animation: move 1100ms ease-in-out; } -
11:43 - scroll-behavior: auto
html { scroll-behavior: auto; } -
12:09 - scroll-behavior: smooth
html { scroll-behavior: smooth; } -
13:10 - :focus-visible & accent-color
/* :focus-visible & accent-color */ :focus-visible { outline: 4px solid var(--green); box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3); } :root { accent-color: var(--green); } -
14:50 - Font palette dark mode & light mode
/* Dark mode */ font-palette: dark; /* Light mode */ font-palette: light; -
15:01 - Font palette custom colors
/* Dark mode */ font-palette: dark; /* Light mode */ font-palette: light; /* Custom colors */ @font-palette-values --MyPalette { override-colors: 1 yellow; } #logo { font-palette: --MyPalette; } -
15:55 - CSS Grid
/* Grid to layout cards */ main { display: grid; grid-template-columns: repeat(auto-fit, minmax(225px, 1fr)); gap: 1rem; } /* Grid to layout each card’s content */ article { display: grid; grid-row: span 5; } -
16:35 - Adding sub grid
/* Grid to layout cards */ main { display: grid; grid-template-columns: repeat(auto-fit, minmax(225px, 1fr)); gap: 1rem; } /* Grid to layout each card’s content */ article { display: grid; grid-row: span 5; /* Adding subgrid, tying them together */ grid-template-rows: subgrid; } -
21:15 - Web App Manifest file icons
// Manifest file "icons": [ { "src": "orange-icon.png", "sizes": "120x120", "type": "image/png" } ] -
21:29 - apple-touch-icon
<!-- HTML head --> <link rel="apple-touch-icon" href="blue-icon.png" /> -
22:36 - Broadcast Channel
// State change broadcastChannel.postMessage("Item is unavailable"); -
23:14 - Origin private file system
// Accessing the origin private file system const root = await navigator.storage.getDirectory(); // Create a file named Draft.txt under root directory const draftHandle = await root.getFileHandle("Draft.txt", { "create": true }); // Access and read an existing file const existingHandle = await root.getFileHandle("Draft.txt"); const existingFile = await existingHandle.getFile(); -
25:32 - Shared Worker
// Create Shared Worker let worker = new SharedWorker("SharedWorker.js"); // Listen for messages from Shared Worker worker.port.addEventListener("message", function(event) { console.log("Message received from worker: " + event); }); // Send messages to Shared Worker worker.port.postMessage("Send message to worker"); -
25:56 - findLast() and findLastIndex()
const list = ["shirt","pants","shoes","hat","shoestring","dress"]; const hasShoeString = (string) => string.includes("shoe"); console.log(list.findLast(hasAppString)); // shoestring console.log(list.findLastIndex(hasAppString)); // 4 -
26:17 - at()
const list = ["shirt","pants","shoes","hat","shoestring","dress"]; // Instead of this: console.log(list[list.length - 2]); // It's as easy as: console.log(list.at(-2)); -
29:12 - strict-dynamic source expression
// strict-dynamic source expression // Without strict-dynamic Content-Security-Policy: script-src desired-script.com dependent-script-1.com dependent-script-2.com dependent-script-3.com; default-src "self"; // With strict-dynamic Content-Security-Policy: default-src "self"; script-src "nonce-desired" "strict-dynamic";
-