ภาพถ่ายโซเชียลมีเดียโดย Andre Taissin บน Unsplash
วิธีที่ง่ายที่สุดในการเพิ่มองค์ประกอบ DOM ในตัว:
ไม่จำเป็นต้องใช้โพลีฟิล เบ ราว์เซอร์สมัยใหม่ทั้งหมดใช้งานได้™️
คุณสามารถขยาย HTML , SVG หรือเนมสเปซที่กำหนดเองอื่นๆ เช่น MathML ได้โดยไม่มีปัญหา
องค์ประกอบต่างๆ สามารถสร้างขึ้นตั้งแต่เริ่มต้นหรืออัพเกรดได้ตามความต้องการเพื่อให้ ความชุ่มชื้นอย่างงดงาม
พอดีกับ 313 ไบต์ (คอร์) หรือ 774 ไบต์ พร้อมการเรียกกลับวงจรชีวิตองค์ประกอบที่กำหนดเอง (ไม่มีอะไรใหม่ให้เรียนรู้)
ตัวอย่างนี้สามารถทดสอบได้จริงและเป็นเพียงรอยขีดข่วนบนพื้นผิวของสิ่งที่สามารถทำได้กับโมดูลที่เล็กมาก แต่ทรงพลังนี้
// const createRegistry = need('nonchalance');นำเข้า createRegistry จาก 'nonchalance/core';// การส่งออกเริ่มต้นจะยอมรับทางเลือก `globalThis` like// บริบทสำหรับสภาพแวดล้อมทั้งหมดที่ไม่มี DOM ดั้งเดิม/ / รีจิสตรีดังกล่าวสามารถเปิดเผยชื่อคลาสที่ผ่านการรับรองพร้อมการอ้างอิง `เอกสาร`// ที่จะใช้ในการสร้างองค์ประกอบ const {HTML} = createRegistry();// ขยายองค์ประกอบใด ๆ เพื่อสร้างหรืออัปเกรดองค์ประกอบที่กำหนดเอง// จากรีจิสทรีที่ไม่แชร์อะไรกับคลาสบริบทส่วนกลาง รหัสผ่านขยาย HTML.Input { // จะสืบทอดฟิลด์แท็กแบบคงที่ = "อินพุต" ตัวสร้าง (...args) {super(...args);this.type = 'รหัสผ่าน'; - // หลีกเลี่ยงสคริปต์ที่เป็นอันตรายเรียกค้นรหัสผ่านได้อย่างง่ายดาย รับค่า () {กลับมา '********'; - // กรณีสาธิต: ยังคงใช้ `value` ดั้งเดิมเมื่อมีการตั้งรหัสผ่าน ตั้งค่า (ความลับ) {super.value = ความลับ; }}document.body.innerHTML = ` <form> <input type="text" name="user" placeholder="user"> <input type="password" name="password" placeholder="password"> <input type="submit"> </form>`;// อัปเกรดองค์ประกอบที่ต้องการผ่านรหัสผ่าน ClassTypenew ใหม่ (document.querySelector('[type="password"]'));// หรือสร้าง instanceconst Secret ใหม่ = Object.assign(รหัสผ่านใหม่, { ชื่อ: 'ผ่าน', ค่า: Math.random() ตัวยึด: 'รหัสผ่านรันไทม์'});const form = document.querySelector('form');form.insertBefore(secret, form.lastElementChild);
การใช้โมดูลฟังก์ชันแบบกำหนดเอง ทำให้สามารถ อัปเกรด องค์ประกอบประเภทใดก็ได้โดยไม่ต้องพบกับข้อผิดพลาด Illegal Constructor ซึ่งจะปรากฏขึ้นทุกครั้งที่ class extends HTMLSomethingElement {}
เมื่อคลาสดังกล่าวไม่ได้ถูกกำหนดไว้ทั่วโลกเป็นรายการใน รีจิสทรี customElements
ไม่เพียงแต่จะไม่มีการแชร์สิ่งใดทั่วโลกผ่านโมดูลนี้ในบริบทระดับโลก งานพิเศษทุกอย่างที่น่าอึดอัดใจเพื่อให้การทำงานแบบบิวด์อินขยายนั้นไม่จำเป็นเลย:
องค์ประกอบใหม่หรือองค์ประกอบที่ส่งผ่านจะรักษาห่วงโซ่รูตต้นแบบไว้เสมอ
ไม่มีคุณลักษณะพิเศษหรือชื่อที่ขัดแย้งกันเกิดขึ้นได้
ยิ่งไปกว่านั้น เนื่องจากสามารถสร้าง รีจิสทรี HTML สำหรับแต่ละโมดูลหรือโปรเจ็กต์เพื่อแชร์ระหว่างส่วนประกอบต่างๆ ได้ จึงเป็นไปได้ที่จะส่งผ่านไปยังการสร้าง รีจิสทรี ดังกล่าว สภาพแวดล้อมที่คล้ายคลึงกัน globalThis
ปลอมหรือเยาะเย้ยนี้ โดยมีอย่างน้อยฟิลด์ document
ที่เปิดเผย createElementNS(namespace, tagName)
และคลาสตั้งแต่หนึ่งคลาสขึ้นไปที่โปรเจ็กต์มีไว้เพื่อทดสอบ เช่น HTMLElement
และ/หรือคลาสอื่นๆ ที่จำเป็นสำหรับโปรเจ็กต์ดังกล่าวให้ประสบความสำเร็จ
อย่างไรก็ตาม เนื่องจากเป้าหมายหลักของโมดูลนี้คือ DOM การอ้างอิง globalThis
จึงถูกใช้เป็นค่าเริ่มต้นที่สมเหตุสมผล แต่ก็ยังไม่ได้หมายความว่ามีการแบ่งปันสิ่งใด ๆ ในรีจิสทรีที่สร้างขึ้นผ่านการส่งออกเริ่มต้น
เลขที่ . วิธีการทำงานของ custom-function
สามารถสรุปได้ดังนี้:
# a native <p> protoype chain HTMLParagraphElement -> HTMLElement -> Element -> Node # a <p> passed to new (class CustomP extends HTML.P {}) CustomP -> HTMLParagraphElement -> HTMLElement -> Element -> Node # a <p> passed to class AnotherP extends CustomP {} AnotherP -> CustomP -> HTMLParagraphElement -> HTMLElement -> Element -> Node
กล่าวอีกนัยหนึ่งก็คือ การสร้างองค์ประกอบผ่าน new AnotherP
หรืออัปเกรดองค์ประกอบผ่าน new AnotherP(liveParagraph)
เพียงอัปเดตเชนต้นแบบ โดยไม่ต้องให้องค์ประกอบออกจาก DOM หรือเปลี่ยนลักษณะดั้งเดิมของมัน เนื่องจากสิ่งนั้นถูกรักษาไว้ในห่วงโซ่การสืบทอดต้นแบบ .
สรุป: การลงทะเบียน แบบ nonchalance เพียงอัปเกรดองค์ประกอบโดยไม่เปลี่ยนธรรมชาติ เช่นเดียวกับวิธีเดียวกับที่บิวด์อินดั้งเดิมขยายการทำงานภายใต้ประทุน
ใช่ ไม่ว่าจะผ่าน /jsx
ส่งออกหรือผ่าน /ref
เกี่ยวกับ /jsx โปรดดูที่ /jsx การส่งออกคืออะไร ส่วน.
เกี่ยวกับ /ref โปรดดูว่า /ref ส่งออกคืออะไร ส่วน.
การเอ็กซ์พอร์ต disconnectedCallback
/ce
จะอัป observedAttributes
องค์ประกอบโดยอัตโนมัติในลักษณะที่เข้ากัน attributeChangedCallback
กับเมธอดของคลาส connectedCallback
โมดูลใช้เวอร์ชันที่ได้รับการปรับแต่งอย่างละเอียดของโมดูลองค์ประกอบที่กำหนดเองซึ่งทำงานได้ดีอยู่แล้ว
ดูการสาธิตสดบน codepen เพื่อทำความเข้าใจเกี่ยวกับวิธีการทำงาน
เลขที่ . ในเชิงเปรียบเทียบ องค์ประกอบ HTML มีทั้งความหมายเชิงความหมายและความหมายที่ชัดเจนและเป็นที่ต้องการของยูทิลิตี้เมื่อใช้งานจริง เช่นเดียวกับที่ฟังก์ชัน JS จะเป็นฟังก์ชัน JS ตลอดไป แม้ว่า Object.setPrototypeOf(() => {}, Number.prototype)
เกิดขึ้น ...คุณเห็นหรือเห็นด้วยว่ามันผิดแค่ไหน?
โมดูลนี้ไม่ต้องการ (และอาจไม่สามารถ) ป้องกันการใช้งานฟีเจอร์ในทางที่ผิด ดังนั้นโปรดตรวจสอบให้แน่ใจว่าเมื่อใดก็ตามที่องค์ประกอบได้รับการอัปเกรด โมดูลนี้จะรักษาสายโซ่ต้นแบบดั้งเดิมไว้เบื้องหลัง หรือคุณจะต่อสู้กับ DOM เพียงลำพัง ..ซึ่งค่อนข้างไม่สะดวกหากถามผม ?
กล่าวโดยสรุป ในทำนองเดียวกัน customElements.define('my-link', class extends HTMLDivElement {}, {extends: 'a'})
ไม่สมเหตุสมผลเลย โมดูลนี้เชื่อว่าผู้ใช้จะต้องหลีกเลี่ยงคลาสที่ไม่มีความหมาย
ในปัจจุบัน ค่าเริ่มต้น / การส่งออกหลักสำหรับโมดูลนี้ชี้ไปที่การส่งออก /core
เดียวกัน
เนื่องจากโมดูลนี้เปิดกล่องแพนโดร่าด้วยความเรียบง่ายและขนาดโค้ดไอระเหย และส่วนใหญ่เป็นเพราะโมดูลยังอยู่เบื้องหลังเวอร์ชัน 0.
ฉันจึงพยายามพิจารณาว่าควรรวมอะไรไว้ในดัชนี และนี่คือความคิดบางส่วนของฉัน:
คงจะดีไม่น้อยถ้ามีโมดูลที่ใช้ ESX ซึ่งเข้าใจส่วนประกอบที่กำหนดด้วยวิธีนี้
คงจะดีไม่น้อยถ้ามีฟังก์ชัน JSX pragma ที่สร้างส่วนประกอบผ่านโมดูลนี้
คงจะดีไม่น้อยถ้ามี ... (เจ้าที่ตรงนี้) ... ?
ใช่ มันคงจะดีมาก และถ้าฉันสามารถตัดสินใจได้ว่าควรจะตั้งชื่อการส่งออกเริ่มต้นอย่างไร ฉันพร้อมที่จะนำชื่อนั้นมารวมกับชื่ออื่นๆ เพื่อเป็นรายการเริ่มต้นสำหรับโมดูลนี้ ... คอยติดตามหรือโปรดให้ฉันด้วย ความคิดและคำแนะนำเกี่ยวกับวิธีการทำเช่นนั้น
ในระหว่างนี้ โปรดใช้การส่งออกที่ชัดเจนเพื่อให้แน่ใจว่าการอัปเดตในอนาคตจะไม่ยุ่งกับตรรกะของคุณ และเราขออภัยหากการเปลี่ยนแปลงล่าสุดทำให้คุณประสบปัญหา แต่ฉันค่อนข้างมั่นใจว่าคุณสามารถเชื่อมโยงหรือเข้าใจได้อย่างง่ายดายว่าเป็นผลดี!
เมื่อองค์ประกอบได้รับการอัพเกรดจากระยะไกล อาจเป็นไปได้ว่าสิ่งเหล่านี้มีคุณสมบัติบางอย่างติดอยู่ซึ่งไม่มีโอกาสผ่านตัวเข้าถึงของพวกเขา
ตัวช่วยนี้เพียงแต่ทำให้แน่ใจว่าคุณสมบัติที่สืบทอดมาจะถูกลบออกจากองค์ประกอบคีย์ของตัวเอง จากนั้นจึงถูกทริกเกอร์ให้เป็นผู้เข้าถึงหลังจากนั้น
นำเข้า createRegistry จาก 'nonchalance/ce'; นำเข้า accessors จาก 'nonchalance/accessors'; const {HTML} = createRegistry();class WithAccessors ขยาย HTML.Div { ตัวสร้าง (...args) {ตัวเข้าถึง (ซุปเปอร์ (...args)); - รับค่า () {console.log ('รับค่า', this._value); ส่งคืน this._value; - ตั้งค่า (_value) {this._value = _value;console.log('set value', this._value); }}// Native div elementconst div = document.createElement('div');div.value = 123;// อัปเกรดใหม่ WithAccessors(div);// re-checkconsole.log(div.value);
ดูสดเพื่อทดสอบเพิ่มเติม
การส่งออก /builtin
(248 ไบต์) เหมือนกับ /core
ทุกประการ ยกเว้นว่าไม่ได้ ใช้ custom-function
เบื้องหลัง ซึ่งหมายความว่า:
เป็นไปไม่ได้สำหรับ new BuiltIn()
หรือสร้าง new BuiltIn(element)
เนื่องจากจะทำให้เกิดข้อผิดพลาด เว้นแต่จะไม่ได้ลงทะเบียนเป็น customElement บิวด์อินขยาย
สามารถใช้เพื่อทำให้การลงทะเบียนส่วนประกอบเป็นแบบอัตโนมัติ ดังที่แสดงในการสาธิตสดนี้บน CodePen
ข้อแม้สำคัญเพียงอย่างเดียวเกี่ยวกับการส่งออกนี้คือ เนื่องจากอิงตามองค์ประกอบที่กำหนดเองมาตรฐานจริง จึงอาจจำเป็นต้องใช้โพลีฟิลในตัวสำหรับ Safari หรือ WebKit ตัวอย่าง:
<!-- สคริปต์หน้าบนสุดสำหรับ Safari เท่านั้น polyfill --><script>self.chrome ||self.netscape ||document.write('<script src="//unpkg.com/@webreflection/custom-elements -builtin"><x2fscript>');</script>
โปรดทราบ ว่าแม้ว่าทั้งเนมสเปซ HTML
และ SVG
จะได้รับอนุญาตตามค่าเริ่มต้น เนื่องจากส่วนขยายบิวด์อิน องค์ประกอบ custome ไม่ยอมรับการขยาย SVG ดังนั้นในทางปฏิบัติแล้ว มีเพียงการขยาย HTML เท่านั้นที่เป็นไปได้ด้วยการส่งออก /builtin
ปัจจุบัน
การส่งออก ./dummy
ส่วนใหญ่มีไว้สำหรับ SSR โดยให้ยูทิลิตี้เดียวกันทุกประการในการขยายคลาสที่จะมีเฉพาะฟิลด์ tag
แบบคงที่
เมื่อใช้ร่วมกับ /tag
ก็เป็นไปได้ที่จะทำ SSR 100% โดย ไม่ใส่ใจ และให้ความชุ่มชื้นในระยะไกล
นำเข้า createRegistry จาก 'https://unpkg.com/nonchalance/dummy'; นำเข้า createTag จาก 'https://unpkg.com/nonchalance/tag'; const {HTML} = createRegistry();class HelloDiv ขยาย HTML.Div { เชื่อมต่อCallback() {console.log('ฉันอยู่นี่'); }}// สร้างเนมสเปซที่นำมาใช้ซ้ำได้เพื่อ hydroconst nmsp = {HelloDiv};// สร้างแท็ก Transformerconst tag = createTag(nmsp);// ลองจินตนาการถึงการตอบสนองของเซิร์ฟเวอร์แทน// หมายเหตุ: รหัสนี้ใช้เพื่อการสาธิต onlyconsole.log( tag`<!doctype html><script type="module">นำเข้า createRegistry จาก 'https://unpkg.com/nonchalance/ce';const {HTML} = createRegistry();const nmsp = {};สำหรับ (const el ของ document.querySelectorAll('[data-comp]')) { const {comp} = el.dataset; ลบ el.dataset.comp; (เอล);</script><HelloDiv></HelloDiv>` .เข้าร่วม('') .ตัดแต่ง() .replace('const nmsp = {};',`const nmsp = { ${[...Object.entries(nmsp)].map( ([คีย์, ค่า]) => `${key}: ${ ค่า}` ).join(',n')} };` -
การส่งออก /jsx
(976 ไบต์) ยอมรับตัวเลือก createElement
เพิ่มเติมและส่งคืนฟังก์ชัน jsx
ที่สามารถใช้เป็น @jsx pragma เพื่อแปลง เหนือสิ่งอื่นใดที่ทำงานตามค่าเริ่มต้นใน React หรือ Preact รวมถึงคลาสที่ขยายผ่านรีจิสทรี HTML หรือ SVG รวมถึงคุณสมบัติทั้งหมดที่ /ce
นำมาสู่คลาสเหล่านั้น: องค์ประกอบที่กำหนดเอง เช่น วงจรชีวิตที่มีเครื่องเทศอยู่ด้านบน:
คลาสต่างๆ จะได้รับ อุปกรณ์ประกอบฉาก ที่ส่งผ่านองค์ประกอบในคอนสตรัคเตอร์ การเปิดใช้งานสัญญาณ ฟังก์ชันอื่นๆ หรือการจัดการทุกสิ่งที่เป็นไปได้แล้วที่จะจัดการโดยคอมโพเนนต์ JSX เริ่มต้น
เมื่อเรียกใช้คอนสตรัคเตอร์ อิลิเมนต์จะเต็มไปด้วยลูกๆ ของมันแล้ว หลีกเลี่ยงปัญหาที่เป็นไปได้ที่รู้จักในอิลิเมนต์แบบกำหนดเองมาตรฐาน เมื่อคลาสถูกกำหนด/ลงทะเบียนก่อนที่จะแยกวิเคราะห์เอกสาร
คล้ายกับ /builtin
ขยายแม้ว่าจะเป็นไปไม่ได้ new Component(props)
แต่ก็เป็นไปได้เสมอ <Component {...props} />
ดูมันใช้ในทางปฏิบัติกับ React live บน CodePen
DOM ก็คือ DOM ไม่ว่าจะมีทางอ้อมกี่ทางก็ตาม DX ของคุณอาจแตกต่างกันไปตามคุณสมบัติของเฟรมเวิร์ก แต่ถ้า React คือสิ่งที่คุณต้องการ จะมีวิธีเล็กๆ น้อยๆ ที่หรูหราและอิง ref
ในการโปรโมตโหนด JSX ปกติด้วย nonchalance/core หรือ nonchalance/ce :
นำเข้าอ้างอิงจาก 'nonchalance/ref';// ระบุว่า Component จะถูกส่งผ่านเป็นข้อมูลอ้างอิง // หมายเหตุ: นี่เป็นเพียง light Proxy ที่ให้ความสมบูรณ์ของคลาส // โดยไม่คำนึงถึงการใช้งานใน wildconst Component = อ้างอิง (คลาสขยาย HTML ดิวิชั่น { ตัวสร้าง (...args) {super(...args);this.addEventListener('คลิก', console.log); }});ReactDOM.render( <div ref={Component}>คลิกฉัน</div>, เอกสาร.ร่างกาย);
ยูทิลิตี้ ref
ยังสามารถใช้เป็นมัณฑนากรได้ และไม่ส่งผลกระทบต่อคุณลักษณะใดๆ ของคลาส ที่ไม่ใส่ใจ ทั่วไป นอกจากนี้ แต่ละองค์ประกอบจะได้รับการอัปเกรดเพียงครั้งเดียว เพื่อความปลอดภัยในการเพิ่ม Listener หรือตรรกะในตัวสร้าง
ดูการสาธิตนี้สดบน Codepen เพื่อทดลองเล่น
การส่งออก /selector
(796 ไบต์) อนุญาตการกำหนดสดของตัวเลือก CSS ใด ๆ เพื่อให้คลาสที่เกี่ยวข้องอัปเกรดองค์ประกอบใด ๆ ที่ตรงกับตัวเลือกนั้นโดยอัตโนมัติ
โปรดทราบว่าตัวเลือกดังกล่าวควร ไม่ซ้ำกันมากที่สุดเท่าที่จะเป็นไปได้ มิฉะนั้นอาจเกิดความประหลาดใจได้ ใช้คลาสหรือแอตทริบิวต์ data-
เฉพาะเพื่ออธิบายตัวเลือกของคุณให้ดีที่สุด
นำเข้า createRegistry จาก 'nonchalance/core';นำเข้า { กำหนด } จาก 'nonchalance/selector';const { HTML } = createRegistry();const Special = Define('[data-comp="special"]', คลาสขยาย HTML ดิวิชั่น { Constructor(...args) {super(...args);this.textContent = 'ฉันพิเศษ!'; }});// จะมีข้อความ "ฉันพิเศษ!" ข้อความครั้งเดียว livedocument.body.innerHTML = `<div data-comp="special"></div>`;
การส่งออก ./tag
tag (188 ไบต์) ช่วยให้สามารถแปลงเทมเพลตในลักษณะที่เป็นมิตรต่อไฮเดรชั่น
สามารถใช้เป็นค่ากลางหลังแท็กลิเทอรัลเทมเพลตที่มีความสามารถเต็มรูปแบบ และไฮเดรชั่นสามารถเกิดขึ้นได้เมื่อองค์ประกอบเหล่านั้นเข้าสู่ DOM
นำเข้า createRegistry จาก 'nonchalance/ce'; นำเข้า createTag จาก 'nonchalance/tag'; const {HTML} = createRegistry (); คลาส HelloDiv ขยาย HTML.Div { เชื่อมต่อCallback() {console.log('ฉันอยู่นี่'); }}// สร้างเนมสเปซที่นำมาใช้ซ้ำได้เพื่อ hydroconst nmsp = {HelloDiv};// สร้างแท็ก Transformerconst tag = createTag(nmsp);// demodocument.body.innerHTML ที่รวดเร็วและสกปรก = tag`<HelloDiv />`.join( '');// ตัวอย่างไฮเดรชั่นสำหรับ (const el ของ document.querySelectorAll('[data-comp]')) { const {comp} = el.ชุดข้อมูล; ลบ el.dataset.com; // อัพเกรดองค์ประกอบหนึ่งครั้ง ใหม่ nmsp[คอมพ์](el);}
ดูสดบน CodePen
ใช่ . การส่งออกทั้ง /core
และ /ce
ทำให้สามารถสร้างทั้งรีจิสทรี HTML และ SVG ตามค่าเริ่มต้น:
นำเข้า createRegistry จาก 'nonchalance/core';const {HTML, SVG} = createRegistry();class Circle ขยาย SVG.Circle { ตัวสร้าง (ตัวเลือก) {Object .assign(super(), options) .setAttribute('fill', 'gold'); - ตั้ง cx (ค่า) { this.setAttribute ('cx', ค่า) } set cy (ค่า) { this.setAttribute ('cy', ค่า) } set r(value) { this.setAttribute('r', value) }}document.querySelector('svg').append( วงกลมใหม่ ({cx: 100, cy: 100, r: 50}));
ดูสดบน codepen
นอกจากนี้ยังเป็นไปได้ที่จะส่งผ่าน เนมสเปซ ใด ๆ ไปยัง createRegistry(options)
โดยใช้ {MathML: "http://www.w3.org/1998/Math/MathML"}
เป็นตัวอย่าง
อนุญาตให้ใช้เนมสเปซใดๆ ที่มีความหมายต่อ document.createElementNS
ได้ โดยไม่มีข้อจำกัดว่าองค์ประกอบ DOM ประเภทใดที่เราสามารถอัปเกรดได้
ก่อนหน้านี้ฉันมีคำตอบที่ยาวมาก แต่สรุปก็คือโมดูลนี้ใช้ มาตรฐาน ตามที่ W3C , WHATWG หรือ ECMAScript กำหนดไว้ และต้องใช้พื้นที่น้อยกว่า 1KB จึงจะทำงานได้ทุกที่
นี่ไม่ใช่โพลีฟิล แต่เป็นยูทิลิตี้ที่ช่วยให้คุณเขียนส่วนประกอบในโลก JS และไม่ต้องกังวลว่าสิ่งเหล่านี้จะขัดแย้งกัน ต้องใช้เครื่องมือ หรือไม่สามารถพกพาข้ามโปรเจ็กต์เป้าหมายใดๆ ที่คุณชอบ/ต้องการ/ชอบได้
กล่าวโดยสรุป หากคุณตกลงที่จะเพิ่มน้อยกว่า 1K ไบต์เพื่อส่งมอบส่วนประกอบสากลสำหรับทั้ง Front End และ Back End world คุณได้เข้าสู่โมดูลที่ถูกต้องแล้ว
ไม่มีอะไรจะโล่งใจไปกว่าการเป็นเด็กประมาทที่เล่นโคลนกับทุกคน " อย่าทำแบบนั้น! " นักคิด
โมดูลนี้แสดงให้เห็นถึงความรู้สึกผ่านฟีเจอร์ JS ที่ทันสมัยที่เป็นอิสระ ซึ่งแสดงให้เห็นถึงทางเลือกที่หรูหรา พกพาสะดวก และมีน้ำหนักเบาเป็นพิเศษ เมื่อเทียบกับความซับซ้อนที่เพิ่มขึ้นอย่างต่อเนื่องที่นำเสนอโดยผู้จำหน่ายเบราว์เซอร์และข้อกำหนดที่ทันสมัย ทั้งหมดนี้จำเป็นในการบังคับให้นักพัฒนาแก้ไขความสามารถในการขยาย บิวด์อินและรักษาทั้งความเรียบง่ายและการเข้าถึงที่ยอดเยี่ยมซึ่งเว็บมีชื่อเสียง