forked from w3ctag/design-principles
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.bs
3220 lines (2575 loc) · 133 KB
/
index.bs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<pre class="metadata">
Title: Web Platform Design Principles
Group: tag
Shortname: design-principles
Repository: w3ctag/design-principles
Status: ED
Level: none
TR: https://www.w3.org/TR/design-principles/
ED: https://w3ctag.github.io/design-principles/
Issue Tracking: GitHub https://github.com/w3ctag/design-principles/issues/
Editor: Sangwhan Moon, w3cid 42399, Google https://www.google.com/, https://sangwhan.com
Former Editor: Domenic Denicola, Google https://www.google.com/, https://domenic.me/, [email protected]
Former Editor: Travis Leithead, Microsoft, [email protected]
Abstract: This document contains a set of design principles to be used when designing web platform technologies. These principles have been collected during the Technical Architecture Group's discussions in <a href="https://github.com/w3ctag/design-reviews/">reviewing</a> developing specifications, and build upon the Ethical Web Principles [[ETHICAL-WEB]]. We encourage specification designers to read this document and use it as a resource when making design decisions.
Default Biblio Status: current
Markup Shorthands: markdown on
Boilerplate: feedback-header off
!By: <a href="https://www.w3.org/2001/tag/">Members of the TAG</a>, past and present
!Participate: <a href="https://github.com/w3ctag/design-principles">GitHub w3ctag/design-principles</a> (<a href="https://github.com/w3ctag/design-principles/issues/new">file an issue</a>; <a href="https://github.com/w3ctag/design-principles/issues?state=open">open issues</a>)
Link Defaults: html (dfn) queue a task/in parallel/reflect
</pre>
<pre class="link-defaults">
spec:css-cascade-5; type:dfn; text:inherit
spec:dom
type:dfn; text:aborted flag
type:method; for:Document; text:getElementsByTagName(qualifiedName)
type:method; for:Document; text:createElement(qualifiedName)
spec:html; type:dfn; for:/
text:focus update steps
text:task queue
text:event loop
spec:html; type:element-attr; for:a; text:href
spec:html; type:event; text:resize
spec:selectors-4; type:selector; text::hover
spec:webidl; type:dfn; text:namespace
</pre>
<!-- Some of these 'anchors' entries are really routing around spec bugs.
https://github.com/w3c/remote-playback/issues/137
https://github.com/whatwg/html/issues/5515
https://github.com/whatwg/html/issues/6053
https://github.com/whatwg/url/issues/522
-->
<pre class="anchors">
urlPrefix: https://dom.spec.whatwg.org/; spec: DOM
url: #dom-document-getelementsbytagname; type: interface; for: Document; text: getElementsByTagName
url: #dom-document-createelement; type: interface; for: Document; text: createElement
urlPrefix: https://w3c.github.io/DOM-Parsing/; spec: DOM-Parsing
url: #dom-innerhtml-innerhtml; type: attribute; for: Element; text: innerHTML
urlPrefix: https://tc39.github.io/ecma262/; spec: ECMA262
url: #sec-bigint-objects; type: interface; text: BigInt
url: #sec-date-objects; type: interface; text: Date
url: #sec-error-objects; type: interface; text: Error
url: #sec-finalization-registry-objects; type: interface; text: FinalizationRegistry
url: #sec-number-objects; type: interface; text: Number
url: #sec-weak-ref-objects; type: interface; text: WeakRef
urlPrefix: https://html.spec.whatwg.org/multipage/; spec: HTML
url: system-state.html#dom-navigator-online; type: attribute; for: NavigatorOnline; text: onLine;
urlPrefix: https://w3c.github.io/remote-playback/; spec: REMOTE-PLAYBACK
url: #remoteplayback-interface; type:interface; text: RemotePlayback
url: #dfn-remote-playback-devices; type:dfn; text: remote playback device
urlPrefix: https://url.spec.whatwg.org/; spec: URL
url: #percent-encode; type: abstract-op; text: percent-encode
urlPrefix: https://www.w3.org/TR/payment-request/; spec: payment-request
url: #dfn-state; type: dfn; text: [[state]];
</pre>
<style>
table.data {
text-align: left;
font-size: small;
}
</style>
<h2 id="basic-principles">Principles behind design of Web APIs</h2>
The Design Principles are directly informed by the ethical framework
set out in the Ethical Web Principles [[ETHICAL-WEB]].
These principles provide concrete practical advice
in response to the higher level ethical responsibilities
that come with developing the web platform.
<h3 id="priority-of-constituencies">Put user needs first (Priority of Constituencies)</h3>
If a trade-off needs to be made,
always put user needs above all.
Similarly, when beginning to design an API,
be sure to understand and document the user need that the API aims to address.
[The internet is for end users](https://tools.ietf.org/html/rfc8890):
any change made to the web platform has the potential to
[affect vast numbers of people](https://www.w3.org/2001/tag/doc/ethical-web-principles/#allpeople),
and may have a profound impact on any person's life. [[RFC8890]]
User needs come before the needs of web page authors,
which come before than the needs of user agent implementors,
which come before than the needs of specification writers,
which come before theoretical purity.
Like all principles,
this isn't absolute.
Ease of authoring affects how content reaches users.
User agents have to prioritize finite engineering resources,
which affects how features reach authors.
Specification writers also have finite resources,
and theoretical concerns reflect underlying needs of all of these groups.
See also:
* [The web should not cause harm to society](https://www.w3.org/2001/tag/doc/ethical-web-principles/#noharm)
* [The web must enhance individuals' control and power](https://www.w3.org/2001/tag/doc/ethical-web-principles/#control)
* [[RFC8890]]
<h3 id="safe-to-browse">It should be safe to visit a web page</h3>
When adding new features,
design them to preserve the user expectation
that visiting a web page is generally safe.
The Web is named for its hyperlinked structure.
In order for the web to remain vibrant,
users need to be able to expect that merely visiting any given link
won't have implications for the security of their computer,
or for any essential aspects of their [privacy](https://www.w3.org/2001/tag/doc/ethical-web-principles/#privacy).
For example, an API which allows any website to
[detect the use of assistive technologies](#do-not-expose-use-of-assistive-tech)
may make users of these technologies feel unsafe visiting unknown web pages,
since any web page may detect this private information.
If users have a realistic expectation of safety,
they can make informed decisions
between Web-based technologies and other technologies.
For example, users may choose to use a web-based food ordering page,
rather than installing an app,
since installing a native app is riskier than visiting a web page.
To work towards making sure the reality of safety on the web matches users' expectations,
we can take complementary approaches when adding new features:
* We can improve the user interfaces through which the Web is used
to make it clearer what users of the Web should (and should not) expect;
* We can change the technical foundations of the Web
so that they match user expectations of privacy;
* We can consider the cases where users would be better off
if expectations were higher,
and in those cases
try to change both technical foundations and expectations.
A new feature which introduces safety risks may still improve user safety overall,
if it allows users to perform a task more safely on a web page
than it would be for them to install a native app to do the same thing.
However, this benefit needs to be weighed against the common goal
of users having a reasonable expectation of safety on web pages.
See also:
* [Security and Privacy Self-Review](https://www.w3.org/TR/security-privacy-questionnaire/)
<h3 id="trusted-ui">Trusted user interface should be trustworthy</h3>
Consider whether new features impact trusted user interfaces.
Users depend on trusted user interfaces
such as the address bar, security indicators and permission prompts,
to understand who they are interacting with and how.
These trusted user interfaces must be able to be designed in a way
that enables users to trust [and verify](https://www.w3.org/2001/tag/doc/ethical-web-principles/#verify)
that the information they provide is genuine,
and hasn't been spoofed or hijacked by the website.
If a new feature allows untrusted user interfaces
to resemble trusted user interfaces,
this makes it more difficult for users to understand what information is trustworthy.
<p class="example">
For example, JavaScript {{alert()}} allows a page to show a modal dialog which looks like part of the browser.
This is often used to attempt to trick users into visiting scam websites.
If this feature was proposed today, it would probably not proceed.
</p>
<h3 id="consent">Ask users for meaningful consent when appropriate</h3>
If a useful feature has the potential to cause harm to users,
make sure that the user can give *[meaningful consent](https://www.w3.org/2001/tag/doc/ethical-web-principles/#control)* for that feature to be used,
and that they can refuse consent effectively.
In order to give *meaningful consent*, the user must:
- **understand** what permission they may choose whether to grant the web page
- be able to choose to give or refuse that permission **effectively**.
If a feature is powerful enough to require a user consent,
but it's impossible to explain to a typical user what they are consenting to,
that's a signal that you may need to reconsider the design of the feature.
If a permission prompt is shown,
and the user doesn't grant permission,
the Web page should not be able to do anything
that the user believes they have refused consent for.
By asking for consent,
we can inform the user of what capabilities the web page does or doesn't have,
reinforcing their confidence that <a href="#safe-to-browse">the web is safe</a>.
However, the <a href="#priority-of-constituencies">user benefit</a>
of a new feature must justify the additional burden on users
to decide whether to grant permission for each feature
whenever it's requested by a Web page.
<p class="example">
For example,
the [Geolocation API](https://www.w3.org/TR/geolocation-API/)
grants access to a user's location.
This can help users in some contexts,
like a mapping application,
but may be dangerous to some users in other contexts -
especially if used without the user's knowledge.
So that the user may decide whether their location may be used by a Web page,
a permission prompt should be shown to the user asking whether to grant location access.
If the user refuses permission,
no location information is available to the Web page.
</p>
See also:
* [Security and privacy are essential](https://www.w3.org/2001/tag/doc/ethical-web-principles/#privacy)
<h3 id="devices-platforms">Support the full range of devices and platforms (Media Independence)</h3>
<!-- was "Media Independence" in the HTML Design Principles -->
As much as possible,
ensure that features on the web work across different input and output [devices,
screen sizes, interaction modes, platforms, and media]
(https://www.w3.org/2001/tag/doc/ethical-web-principles/#multi).
One of the main values of the Web is that it's extremely flexible:
a Web page may be viewed on virtually any consumer computing device
at a very wide range of screen sizes,
may be used to generate printed media,
and may be interacted with in a large number of different ways.
New features should match the [existing flexibility](https://www.w3.org/2001/tag/doc/ethical-web-principles/#render)
of the web platform.
<div class="note">
This doesn't imply that features which don't work in *every* possible context should be excluded.
For example, hyperlinks can't be visited when printed on paper,
and the ''click'' event doesn't translate perfectly to touch input devices
where positioning and clicking the pointer occur in the same gesture (a "tap").
These features still work across a wide variety of contexts,
and can be adapted to devices that don't support their original intent -
for example, a tap on a mobile device will fire a ''click'' event as a fallback.
</div>
Features should also be designed so that the easiest way to use them
maintains flexibility.
<div class="example">
The 'display: block',
'display: flex',
and 'display: grid' layout models in CSS
all default to placing content within the available space and without overlap,
so that it works across screen sizes,
and allows users to choose their own font and font size without causing text to overflow.
</div>
<h3 id="leave-the-web-better">Leave the web better than you found it</h3>
As you add new capabilities to the web platform, do so in a way that improves
the overall platform, for example its security or privacy vulnerabilities, or accessibility characteristics.
The existence of a defect in one part of the platform must not be used as a license
for adding or extending such defect into new capabilities and thereby further decreasing
the overall platform quality. Where possible, build new web capabilities that
improve the overall platform quality.
Parts of the web platform evolve independently.
Issues that are present with a certain web technology now may be fixed in a subsequent iteration.
Duplicating these issues makes fixing them more difficult.
By adhering to this principle we can make sure overall platform quality improves over time.
<h2 id="api-across-languages">API Design Across Languages</h2>
<h3 id="simplicity">Prefer simple solutions</h3>
<!-- was "Avoid Needless Complexity" in the HTML Design Principles -->
Look hard for simple solutions to the
<a href="#priority-of-constituencies">user needs</a>
you intend to address.
Simple solutions are generally better than complex solutions,
although they may be harder to find.
Simpler features are easier for user agents to implement and test,
more likely to be interoperable,
and easier for authors to understand.
It is especially important to design your feature so that
the most common use cases are easy to accomplish.
Make sure that your <a href="#priority-of-constituencies">user needs</a>
are well-defined.
This allows you to avoid scope creep,
and make sure that your API does actually meet the needs of all users.
Of course,
complex or rare use cases are also worth solving,
though their solutions may be more complicated to use.
As Alan Kay said,
"simple things should be simple, complex things should be possible."
Do note however that while common cases are often simple,
commonality and complexity are not always correlated.
<div class=example>
Sanitizing HTML to prevent XSS attacks is a complex process
that requires extensive security knowledge,
however the [Sanitizer API](https://wicg.github.io/sanitizer-api/) provides a shortcut for this common use case.
It also permits simpler types of filtering, but with more configuration.
</div>
See also:
* [[LEAST-POWER]]
<h3 id="high-level-low-level">Consider tradeoffs between high level and low level APIs</h3>
<!--
See "High level or low-level APIs?"
https://github.com/w3ctag/design-principles/issues/117
-->
High-level APIs allow user agents more ability to
intervene in various ways [on behalf of the user](#priority-of-constituencies),
such as to ensure accessibility, privacy, or usability.
<div class=example id=font-enumeration>
A font picker (high level API)
[was recommended by the TAG](https://github.com/w3ctag/design-reviews/issues/399)
over a Font Enumeration API (low level API)
as it addresses the bulk of use cases,
while preserving user privacy,
as it is free from the the fingerprinting concerns that accompany
a general Font Enumeration API.
A native font picker also comes with accessibility built-in,
and provides consistency for end users.
</div>
Low-level APIs afford authors room for experimentation
so that high level APIs can organically emerge
from usage patterns over time.
They also provide an escape hatch when the higher-level API
is not adequate for the use case at hand.
Lower level building blocks cannot always be exposed as Web APIs.
A few possible reasons for this are
to preserve the user's security and privacy,
or to avoid tying Web APIs to specific hardware implementations.
However, high level APIs should be designed in terms of
building blocks over lower level APIs
whenever possible.
This may guide decisions on how high level the API needs to be.
A well-layered solution should ensure continuity
of the ease-of-use vs power tradeoff curve
and avoid sharp cliffs
where a small amount of incremental use case complexity
results in a large increase of code complexity.
<h3 id="name-thoughtfully">Name things thoughtfully</h3>
Name APIs with care.
Naming APIs well makes it much easier for authors to use them correctly.
See the more detailed <a href="#naming-is-hard">Naming principles</a> section
for specific guidance on naming.
<h3 id="consistency">Be consistent</h3>
It is good practice to consider precedent in the design of your API
and to try to be consistent with it.
There is often a tension between API ergonomics and consistency,
when existing precedent is of poor usability.
In some cases it makes sense to break consistency to improve usability,
but the improvement should be very significant to justify this.
<!-- TODO: example? -->
Since the web platform has gradually evolved over time,
there are often multiple conflicting precedents
which are mutually exclusive.
You can weigh which precdent to follow by taking into account
prevalence (all else being equal, follow the more popular precedent),
API ergonomics (all else being equal, follow the more usable precedent),
and API age (all else being equal, follow the newer precedent).
<!-- TODO: example? -->
There is often a tension between internal and external consistency.
<em>Internal consistency</em> is consistency with the rest of the system,
whereas <em>external consistency</em> is consistency with the rest of the world.
In the web platform, that might materialize in three layers:
consistency within the technology the API belongs to (e.g. CSS),
consistency with the rest of the web platform,
and in some cases external precedent,
when the API relates to a particular specialized outside domain.
In those cases, it is useful to consider what the majority of users will be.
Since for most APIs the target user is someone who is familiar with the
technology they are defined in,
err on the side of favoring consistency with that.
<div class="example">
One example is
<a href="https://www.w3.org/TR/css-color-4/#funcdef-lab">Lab colors</a>:
It would be more consistent with the rest of CSS to use percentages for L (0%-100%),
but more consistent with the rest of Color Science to use a unitless number (0-100).
There was a lot of heated debate,
which resolved in favor of percentages,
i.e. consistency within CSS.
</div>
There is also a separate section on <a href="#naming-consistency">naming consistency</a>.
<h3 id="feature-detect">New features should be detectable</h3>
Provide a way for authors to programmatically detect
whether your feature is available,
so that web content may gracefully handle the feature not being present.
An existing feature may not be available on a page for a number of reasons.
Two of the more common reasons are
because it hasn't been implemented yet, or
because it's only available in <a href="#secure-context">secure contexts</a>.
Authors shouldn't need to write different code to handle each scenario.
That way, even if an author only knows or cares about one scenario,
the code will handle all of them.
<p class="note">
When a feature is available but isn't feasible to use
because a required device isn't present,
it's better to expose that the feature is available
and have a separate way to detect that the device isn't.
This allows authors to handle a device not being available differently
from the feature not being available,
for example by suggesting the user connect or enable the device.
See [[#device-enumeration]].
</p>
Authors should always be able to detect a feature from JavaScript,
and in some cases the feature should also be detectable
in the language where it's used
(such as ''@supports'' in CSS).
In some cases, it may **not** be appropriate to allow feature detection.
Whether the feature should be detectable or not
should be based on the <a href="#priority-of-constituencies">user need</a>
for the feature:
if there is a user need or design principle which would fail
if feature detection were available for the feature,
then you should not support feature detection.
Also, if a feature is generally not exposed to developers,
it is not appropriate to support feature detection.
For example, private browsing mode is a concept
which is recognised in web specifications,
but not exposed to authors.
For private browsing mode to support the user's needs,
it must not be feature detected.
See also:
* [[#do-not-expose-use-of-private-browsing-mode]]
* [[#do-not-expose-use-of-assistive-tech]]
* [[#secure-context]]
<h3 id="secure-context">Consider limiting new features to secure contexts</h3>
Always limit your feature to secure contexts
if it would pose a risk to the user
without the authentication, integrity, or confidentiality
that's present only in secure contexts.
<div class="example">
One example of a feature that should be limited to secure contexts
is [Geolocation](https://www.w3.org/TR/geolocation-API/),
since it would be a risk to users' privacy to transmit their location in an insecure way.
</div>
For other features, TAG members past and present
haven't reached consensus on general advice.
Some believe that all new features
(other than features which are additions to existing features)
should be limited to secure contexts.
This would help encourage the use of HTTPS,
helping users be more secure in general.
Others believe that features should only be limited to secure contexts
if they have a known security or privacy impact.
This lowers the barrier to entry for creating web pages
that take advantage of new features which don't impact user security or privacy.
<div class="note">
Specification authors can limit most features defined in
<a href="https://heycam.github.io/webidl/">Web IDL</a>,
to secure contexts
by using the
[{{SecureContext}}] extended attribute
on interfaces, namespaces, or their members (such as methods and attributes).
However, for some types of API (e.g., dispatching an event),
limitation to secure contexts should just
be defined in normative prose in the specification.
If this is the case,
consider whether there might be scope for adding a similar mechanism
to [{{SecureContext}}]
to make this process easier for future API developers.
</div>
<div class="note">
As described in [[#feature-detect]],
you should provide a way to programmatically detect whether a feature is available,
including cases where the feature is unavailable because the context isn't secure.
However, if, for some reason
there is no way for code to gracefully handle the feature not being present,
limiting the feature to secure contexts might cause problems
for code (such as libraries) that may be used in either secure or non-secure contexts.
</div>
<h3 id="do-not-expose-use-of-private-browsing-mode">Don't reveal that private browsing mode is engaged</h3>
Make sure that your feature doesn't give authors a way to detect private browsing mode.
Some people use [private browsing mode](https://www.w3.org/2001/tag/doc/private-browsing-modes/)
to protect their own personal safety.
Because of this, the fact that someone is using private browsing mode
may be [sensitive information](https://www.w3.org/TR/security-privacy-questionnaire/#sensitive-data) about them.
This information may [harm](https://www.w3.org/2001/tag/doc/ethical-web-principles/#noharm) people
if it is revealed to a web site controlled by others who have power over them
(such as employers, parents, partners,
or [state actors](https://www.w3.org/2001/tag/doc/ethical-web-principles/#expression)).
Given such dangers,
websites should not be able to detect that private browsing mode is engaged.
<div class="example">
User Agents which support [IndexedDB](https://www.w3.org/TR/IndexedDB/)
should not disable it in private browsing mode,
because that would reveal that private browsing mode is engaged
</div>
<div class="example">
The [Payment Request API](https://www.w3.org/TR/payment-request/)'s
[show() method](https://www.w3.org/TR/payment-request/#show-method),
when called,
allows User Agents <q cite="https://www.w3.org/TR/payment-request/#show-method">to act
as if the user had immediately
[aborted the payment request](https://www.w3.org/TR/payment-request/#dfn-user-aborts-the-payment-request)</q>.
This enables User Agents to automatically abort payment requests
in private browsing mode
(thus protecting [sensitive information](https://www.w3.org/TR/security-privacy-questionnaire/#sensitive-data)
such as the user's shipping or billing address)
without revealing that private browsing mode is engaged.
</div>
See also:
* [Security and privacy are essential](https://www.w3.org/2001/tag/doc/ethical-web-principles/#privacy)
* [What data does this specification expose to an origin?](https://www.w3.org/TR/security-privacy-questionnaire/#underlying-platform-data)
* [[#private-browsing-mode]]
<h3 id="private-browsing-mode">Consider how your API should behave in private browsing mode</h3>
If necessary, specify how your API should behave differently
in private browsing mode.
For example, if your API would reveal information
that would allow someone to correlate
a single user’s activity
both in and out of private browsing mode,
consider possible [mitigations](https://www.w3.org/TR/security-privacy-questionnaire/#mitigations)
such as introducing noise,
or using permission prompts to give the user extra information
to help them meaningfully consent to this tracking (see [[#consent]]).
Private browsing modes enable users to browse the web
without leaving any trace of their private browsing on their device.
Therefore, APIs which provide client-side storage
should not persist data stored
while private browsing mode is engaged
after it's disengaged.
This can and should be done
without revealing any detectable API differences to the site.
<div class="example">
User Agents which support
[localStorage](https://html.spec.whatwg.org/multipage/webstorage.html#dom-localstorage)
should not persist storage area changes
made while private browsing mode is engaged.
If the User Agent has two simultaneous sessions with a site,
one in private browsing mode and one not,
storage area changes made in the private browsing mode session
should not be revealed to the other browsing session,
and vice versa.
(The [storage event](https://html.spec.whatwg.org/multipage/indices.html#event-storage) should not be fired
at the other session's [window object](https://html.spec.whatwg.org/multipage/window-object.html#window).)
</div>
See also:
* [[#do-not-expose-use-of-private-browsing-mode]]
* [Does this specification introduce new state for an origin that persists across browsing sessions?](https://www.w3.org/TR/security-privacy-questionnaire/#persistent-origin-specific-state)
* [Security and privacy self review: Private Browsing](https://www.w3.org/TR/security-privacy-questionnaire/#private-browsing)
<h3 id="do-not-expose-use-of-assistive-tech">Don't reveal that assistive technologies are being used</h3>
Make sure that your API doesn't provide a way
for authors to detect that a user is using assistive technology
without the user's consent.
[The web platform must be accessible to people with disabilities.](https://www.w3.org/2001/tag/doc/ethical-web-principles/#allpeople)
If a site can detect that a user is using an assistive technology,
that site can deny or restrict the user's access to the services it provides.
People who make use of assistive technologies
are often [vulnerable members of society](https://www.w3.org/2001/tag/doc/ethical-web-principles/#noharm);
their use of assistive technologies is [sensitive information](https://www.w3.org/TR/security-privacy-questionnaire/#sensitive-data) about them.
If an API provides access to this information
without the user's [consent](#consent),
this sensitive information may be revealed to others
(including [state actors](https://www.w3.org/2001/tag/doc/ethical-web-principles/#expression))
who may wish them harm.
Sometimes people propose features which aim to improve the user experience
for users of assistive technology,
but which would reveal the user's use of assistive technology as a side effect.
While these are well intentioned,
they violate [[#safe-to-browse]],
so alternative solutions must be found.
<div class="example">
The [Accessibility Object Model](https://wicg.github.io/aom/) (AOM)
used to define a set of events which, when fired,
[revealed the use of assistive technology](https://github.com/WICG/aom/issues/81).
AOM has since removed these events and
[replaced them](https://github.com/WICG/aom/blob/gh-pages/explainer.md#user-action-events-from-assistive-technology) with synthetic DOM events
which don't reveal the use of assistive technology.
</div>
See also:
* [Web Technology Accessibility Guidelines](https://w3c.github.io/apa/fast/)
* [Security and privacy are essential](https://www.w3.org/2001/tag/doc/ethical-web-principles/#privacy)
* [What data does this specification expose to an origin?](https://www.w3.org/TR/security-privacy-questionnaire/#underlying-platform-data)
<h3 id="require-user-activation">Require user activation for powerful APIs</h3>
Some powerful APIs can produce intrusive UI (eg. auto-playing audio),
expose user data (eg. interacting with the clipboard),
perform a background activity without an obvious indicator to the user (eg. accessing local storage),
or prompt the user to interact with [trusted UI](#trusted-ui)
(eg. permission prompts, device hardware features).
These APIs should be designed to require some indication of user intention (such as **user activation**) in order to function.
This indicates that the user is intentionally interacting with the web page in question.
User activation is defined in detail
[in the HTML standard](https://html.spec.whatwg.org/#tracking-user-activation).
You should think about the effect your API has on the user experience,
as well as any risks presented to the user,
when deciding whether user activation needs to only occur
once overall ([sticky](https://html.spec.whatwg.org/#sticky-activation-gated-api)),
periodically ([transient](https://html.spec.whatwg.org/#transient-activation-gated-api)) or
once per API call ([transient consuming](https://html.spec.whatwg.org/#activation-consuming-api)).
Note that while user activation is in many cases necessary,
it is not always *sufficient*
to protect users from invasive behaviours,
and seeking [meaningful consent](#consent) is also important.
<h3 id="support-non-fully-active">Support non-"fully active" documents</h3>
After a user navigated away from a document,
the document might be cached in a non-[=Document/fully active=] state,
and might be reused when the user navigates back to the entry holding the document, which makes navigation fast for users.
In browsers, this is known as the back/forward cache, or "<abbr title="back/forward cache">BFCache</abbr>" for short.
In the past, many APIs have missed specifying support for non-[=Document/fully active=] documents,
making them hard to support in various user agents to cache pages in the BFCache, effectively making the user experience of navigating back and forth less optimal.
To avoid this happening with your API,
you should specify support for non-[=Document/fully active=] documents by following these guidelines:
Note: It is possible for a document to not become [=Document/fully active=] for other reasons not related to
caching, such as when the iframe holding the document gets detached.
Some advices below might not be relevant for those cases,
since the document will never return to [=Document/fully active=] again.
<h4 id="gate-fully-active">Gate actions with [=Document/fully active=] checks</h4>
When performing actions that might update the state of a document,
be aware that the document might not be [=Document/fully active=]
and is considered as "non-existent" from the user's perspective.
This means they should not receive updates or perform actions.
Note: It is possible for a [=Document/fully active=] document to be perceived as "non-existent" by users,
such as when the document is [displaying prerendered content](https://jeremyroman.github.io/alternate-loading-modes/).
These documents might behave differently than non-[=Document/fully active=] documents,
and the guidelines here might not be applicable to them,
as it is written only for handling non-[=Document/fully active=] documents.
In many cases,
anything that happens while the document is not [=Document/fully active=]
should be treated as if it never happened.
If it makes more sense to "update" a document to ensure it does not hold stale information
after it becomes [=Document/fully active=] again, consider the [[#listen-fully-active]] pattern below.
<div class="example">
APIs that periodically send information updates,
such as Geolocation API's {{Geolocation/watchPosition()}}
should not send updates if the document is no longer fully active.
They also should not queue those updates to arrive later,
and only resume sending updates when the document becomes active again,
possibly sending one update with the latest information then.
</div>
<h4 id="listen-fully-active">Listen for changes to [=Document/fully active=] status</h4>
When a document goes from [=Document/fully active=] to non-[=Document/fully active=],
it should be treated similarly to the way discarded documents are treated.
The document must not retain exclusive access to shared resources
and must ensure that no new requests are issued
and that connections that allow for new incoming requests are terminated.
When a document goes from non-[=Document/fully active=] to [=Document/fully active=] again,
it can restore connections if appropriate.
While web authors can manually do cleanup (e.g. release the resources, sever connections)
from within the {{pagehide}} event and restore them from the {{pageshow}} event themselves,
doing this automatically from the API design allows the document to be kept alive after navigation by default,
and is more likely to lead to well-functioning web applications.
<div class="example">
APIs that create live connections can pause/close the connection and possibly resume/reopen it later.
It's also possible to let the connection stay open to complete existing ongoing requests,
and later update the document with the result when it gets restored, if appropriate (e.g.
resource loads).
</div>
<div class="example">
APIs that hold non-exclusive resources
may be able to release the resource when the document becomes not fully active,
and re-acquire them when it becomes [=Document/fully active=] again
(Screen Wake Lock API is already [doing](https://w3c.github.io/screen-wake-lock/#handling-document-loss-of-full-activity) the first part).
</div>
Note: this might not be appropriate for all types of resources,
e.g. if an exclusive lock is held,
we cannot just release it and reacquire when [=Document/fully active=]
since another page could then take that lock.
If there is an API to signal to the page that this has happened,
it may be acceptable but beware that if the only time this happens is with BFCache,
then it's likely many pages are not prepared for it. If it is not possible to support BFCache,
follow the [[#discard]] pattern described below.
Additionally, when a document becomes [=Document/fully active=] again,
it can be useful to update it with the current state of the world,
if anything has changed while it is in the non-[=Document/fully active=] state.
However, care needs to be taken with events that occurred while in the BFCache.
When not [=Document/fully active=], for some cases, all events should be dropped,
in some the latest state should be delivered in a single event,
in others it may be appropriate to queue events or deliver a combined event.
The correct approach is case by case and should consider privacy,
correctness, performance and ergonomics.
Note: Making sure the latest state is sent to a document that becomes
[=Document/fully active=] again is especially important when retrofitting existing APIs.
This is because current users of these APIs expect to always have the latest information.
Dropping state updates can leave the document with stale information,
which can lead to unexpected and hard-to-detect breakage of existing sites.
<div class="example">
The {{gamepadconnected}} event
can be sent to a document that becomes [=Document/fully active=] again
if a gamepad is connected while the document is not [=Document/fully active=].
If the gamepad was repeatedly connected and disconnected,
only the final connected event should be delivered.
(This is not specified yet, see [issue](https://github.com/w3c/gamepad/issues/149))
</div>
<div class="example">
For geolocation or other physical sensors,
no information about what happened while not [=Document/fully active=] should be delivered.
The events should simply resume from when the document became [=Document/fully active=].
However, these APIs should check the state when the document becomes [=Document/fully active=] again,
to determine if a status update should be sent (e.g. is the current location far away from the
location when the document becomes not fully active?), to ensure the document has the latest
information, as guaranteed by the API normally.
</div>
<div class="example">
For network connections or streams,
the data received while not [=Document/fully active=] should be delivered only
when the document becomes [=Document/fully active=] again,
but whereas a stream might have created many events with a small amount of data each,
it could be delivered as smaller number of events with more data in each.
</div>
<h4 id="omit-non-fully-active">Omit non-[=Document/fully active=] documents from APIs that span multiple documents</h4>
Non-[=Document/fully active=] documents should not be observable,
so APIs should treat them as if they no longer exist.
They should not be visible to the "outside world" through document-spanning APIs
(e.g. {{Clients/matchAll()|clients.matchAll()}}, {{Window/opener|window.opener}}).
Note: This should be rare since cross-document-spanning APIs are themselves relatively rare.
<div class="example">
{{BroadcastChannel}} [checks](https://html.spec.whatwg.org/multipage/web-messaging.html#broadcasting-to-other-browsing-contexts:fully-active) for [=Document/fully active=] before sending messages to other browsing contexts.
</div>
<div class="example">
{{Clients/matchAll()|clients.matchAll()}}
currently does not distinguish between [=Document/fully active=]
and non-[=Document/fully active=] clients,
but correct implementations should only return [=Document/fully active=] clients.
(See [issue](https://github.com/w3c/ServiceWorker/issues/1594))
</div>
<h4 id="discard">Discard non-[=Document/fully active=] documents for situations that can't be supported</h4>
If supporting non-[=Document/fully active=] documents is not possible for certain cases,
explicitly specify it by [=discard a document|discarding the document|=] if the situation happens after the user navigated away,
or setting the document's [salvageable](https://html.spec.whatwg.org/multipage/browsing-the-web.html#concept-document-salvageable)
bit to false if the situation happens before or during the navigation away from the document,
to cause it to be automatically discarded after navigation.
Note: this should be rare and probably should only be used when retrofitting old APIs,
as new APIs should always strive to work well with BFCache.
<div class="example">
WebSockets [sets the salvageable bit to false](https://html.spec.whatwg.org/#unloading-documents:concept-document-salvageable-7) during unload.
</div>
<div class="example">
Calling {{Clients/claim()|clients.claim()}}
should not wait for non-[=Document/fully active=] clients,
instead it should cause the non-[=Document/fully active=] client documents to be discarded.
(This is currently not specified, see [issue](https://github.com/w3c/ServiceWorker/issues/1594))
</div>
<h4 id="per-document-state">Be aware that per-document state/data might persist after navigation</h4>
As a document might be reused even after navigation,
be aware that tying something to a document's lifetime
also means reusing it after navigations.
If this is not desirable,
consider listening to changes to the [=Document/fully active=] state
and doing cleanup as necessary (see above).
<div class=example>
[=Sticky activation=] is determined by the "last activation timestamp",
which is tied to a document.
This means after a user triggers activation once on a document,
the document will have sticky activation forever,
even after the user navigated away and back to it again.
Whether this should actually be reset when full activity is lost or not
is still [under discussion](https://github.com/whatwg/html/issues/6588).
</div>
<h3 id="third-party-tools">Prioritize usability over compatibility with third-party tools</h3>
Design new features with usability as the primary goal, and compatibility with third-party tooling as a secondary goal.
The web platform benefits from a wide ecosystem of tooling
to facilitate easier and faster development.
A lot of the time, the syntax of an upcoming web platform feature
may conflict with that of a third-party tool causing breakage.
This is especially common as third-party tools are often used to prototype
new web platform features.
In general, web platform features last a lot longer than most third-party tools,
and thus giving them the optimal syntax and functionality should be of high priority.
In some cases, the conflict will introduce problems across a large number of
web sites, necessitating the feature's syntax to be redesigned to avoid clashes.
<div class="example">
<code>Array.prototype.contains()</code> had to be renamed to
<code>Array.prototype.includes()</code> to avoid clashes with
the identically named but incompatible method from PrototypeJS,
a library that was in use in millions of websites.
</div>
However, these cases should be exceptions.
When deciding whether to break third party tools with new syntax, there are several factors to consider,
such as severity of the breakage,
popularity of the third party tool,
and many more.
Possibly the most important factor is how severely would the usability of the web platform feature be compromised
if its syntax was changed to avoid breaking the third party tool?
If several alternatives of similar usability are being considered,
it is usually preferable to prioritize the ones that inconvenience third party tools the least.
<div class="example">
When the CSS WG was designing [[CSS-GRID-1|CSS Grid Layout]],
square brackets were chosen instead of parentheses for naming grid tracks
to avoid breaking Sass, a popular preprocessor.
</div>
However, if avoiding breaking the third party tool would lead to
a *significant* negative impact on of the feature's usability,
that is rarely an acceptable tradeoff,
unless it causes significant breakage of live websites.
Languages should also provide mechanisms for extensibility
that authors can use to extend the language
without breaking future native functionality,
to reduce such dilemmas in the future.
<h2 id="html">HTML</h2>
This section details design principles for features which are exposed via HTML.
<h3 id="attribute-reuse">Re-use attribute names (only) for similar functionality</h3>
If you are adding a feature that is specified through an HTML attribute,
check if there is an existing attribute name on another element
that specifies similar functionality.
Re-using an existing attribute name means authors can utilize existing knowledge,
maintains [consistency](#consistency) across the language,
and keeps its vocabulary small.
<div class="example">
The same attribute name, <{select/multiple}>,
is used on both <{select}>
to allow selection of multiple values,
as well as on <{input}>
to allow entry of multiple values.
</div>
<div class="example">
The <{details/open}> attribute was introduced on the <{details}> element,
and then re-used by <{dialog}>.
</div>
If you do re-use an existing attribute,
try to keep its syntax as close as possible to the syntax of the existing attribute.
<div class="example">
The <{label/for}> attribute was introduced on the <{label}> element,
for specifying which form element it should be associated with.
It was later re-used by <{output}>,
for specifying which elements contributed
input values to or otherwise affected the calculation.
The syntax of the latter is broader:
it accepts a space-separated list of ids,
whereas the former only accepts one id.
However, they both still conform to the same syntax,
whereas e.g. if one of them accepted a list of ids,
and the other one a selector, that would be an antipattern.
</div>
The inverse also applies:
do **not** re-use an existing attribute name if
the functionality you are adding is **not** similar to that of the existing attribute.
<div class="example">
The `type` attribute is used on the <{input}> and <{button}> elements
to further specialize the element type,
whereas on every other element (e.g. <{link}>, <{script}>, <{style}>)
it specifies MIME type.
This is an antipattern; one of these groups of attributes should have had a different name.
</div>
<h3 id="avoid-html-parser-blocking"> Do not pause the HTML parser</h3>
Ensure that your design does not require HTML parser to pause to handle external resources.
As a page parses,
the browser discovers assets that the page needs,
and figures out a priority in which they should be loaded in parallel.
Such parsing can be disrupted by a resource which blocks the discovery of subsequent resources.
At worst, it means the browser downloads items in series rather than parallel.
At best, it means the browser queues downloads based on speculative parsing,
which may turn out to be incorrect.
Features that block the parser generally do so
because they want to feed additional content into the parser
before subsequent content.
This is the case of legacy `<script src="…">` elements,
which can inject into the parser using `document.write(…)`.
Due to the performance issues above, new features must not do this.
<h3 id="avoid-render-blocking"> Avoid features that block rendering</h3>
Features that require resource loading or other operations before rendering the page,
often result in blank page (or the previous page). The result is a poor user experience.
Consider adding such features only in cases when the overall user experience is improved.
A canonical example of this is blocking rendering in order to download and process a stylesheet.
The alternative user experience is a flash of unstyled content, which is undesirable.
<h2 id="css">Cascading Style Sheets (CSS)</h2>
This section details design principles for features which are exposed via CSS.