browsable 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +12 -0
- data/README.md +240 -0
- data/bin/update-bcd-snapshot +65 -0
- data/data/bcd-snapshot.json +341 -0
- data/exe/browsable +6 -0
- data/lib/browsable/analyzers/base.rb +74 -0
- data/lib/browsable/analyzers/css.rb +82 -0
- data/lib/browsable/analyzers/erb.rb +258 -0
- data/lib/browsable/analyzers/html.rb +11 -0
- data/lib/browsable/analyzers/javascript.rb +81 -0
- data/lib/browsable/cli.rb +333 -0
- data/lib/browsable/config.rb +163 -0
- data/lib/browsable/doctor.rb +189 -0
- data/lib/browsable/finding.rb +41 -0
- data/lib/browsable/formatters/github.rb +50 -0
- data/lib/browsable/formatters/human.rb +162 -0
- data/lib/browsable/formatters/json.rb +20 -0
- data/lib/browsable/policy_detector.rb +267 -0
- data/lib/browsable/policy_scanner.rb +73 -0
- data/lib/browsable/railtie.rb +16 -0
- data/lib/browsable/rake_tasks.rb +28 -0
- data/lib/browsable/report.rb +139 -0
- data/lib/browsable/sources/base.rb +45 -0
- data/lib/browsable/sources/builds.rb +10 -0
- data/lib/browsable/sources/importmap.rb +98 -0
- data/lib/browsable/sources/javascripts.rb +10 -0
- data/lib/browsable/sources/public_assets.rb +9 -0
- data/lib/browsable/sources/stylesheets.rb +9 -0
- data/lib/browsable/sources/views.rb +9 -0
- data/lib/browsable/target.rb +175 -0
- data/lib/browsable/version.rb +5 -0
- data/lib/browsable.rb +47 -0
- data/lib/generators/browsable/install/install_generator.rb +82 -0
- data/lib/generators/browsable/install/templates/browsable.yml.tt +51 -0
- metadata +185 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 8fbd1c4932fbe740cf4d0560fbeb4738c51c3129efdb3c7a3e48b86bc47a743d
|
|
4
|
+
data.tar.gz: f6d98e30cc6e54c6c5fe643dbf3eada45a08af171e2632561c8d91f1b49c74b6
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 5f21b860c35d76a1011a2152a40ab9cbb232e7378d93f61fec3c75f4cea1cd5b69829ea4e77ffd2ae5f7406334e436d4997a17ad41fb769f253362e579d5baa6
|
|
7
|
+
data.tar.gz: 9e996ecdb1dded29f78c2b30c3b5c37178bd7c339800680bca51947934c6addf965534d09a1b3b03b5358b2134b542b056eab354b9582ba9864dc2dc806f57d7
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the `browsable` gem are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0]
|
|
11
|
+
|
|
12
|
+
- Initial release.
|
data/README.md
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# browsable
|
|
2
|
+
|
|
3
|
+
**Rails-aware browser-compatibility auditing for your frontend code.**
|
|
4
|
+
|
|
5
|
+
`browsable` audits a Rails application's CSS, HTML, ERB, and JavaScript and
|
|
6
|
+
reports which browsers can actually render and run it — then compares that
|
|
7
|
+
against the project's declared `allow_browser` policy.
|
|
8
|
+
|
|
9
|
+
The name is a play on Rails 8's `allow_browser` controller API. Instead of
|
|
10
|
+
*declaring* which browsers you allow, `browsable` tells you which browsers your
|
|
11
|
+
code is actually **browsable by**.
|
|
12
|
+
|
|
13
|
+
> This is the core gem of the [`browsable` monorepo](https://github.com/romanhood/browsable).
|
|
14
|
+
> See also [`browsable-lsp`](../browsable-lsp) (editor diagnostics) and
|
|
15
|
+
> [`browsable.nvim`](../browsable.nvim) (Neovim plugin).
|
|
16
|
+
|
|
17
|
+
## Philosophy
|
|
18
|
+
|
|
19
|
+
- **The gem owns no parsing or compat-data logic.** It shells out to mature
|
|
20
|
+
tools that already do this well — [Herb](https://github.com/marcoroth/herb)
|
|
21
|
+
for ERB, [stylelint](https://stylelint.io/) for CSS,
|
|
22
|
+
[eslint-plugin-compat](https://github.com/amilajack/eslint-plugin-compat) for
|
|
23
|
+
JavaScript. The gem's value is the Rails-aware glue.
|
|
24
|
+
- **No `package.json`, no `node_modules` in your Rails repo.** The external
|
|
25
|
+
tools live globally on your machine. `browsable doctor` detects them and
|
|
26
|
+
guides installation.
|
|
27
|
+
- **It reports, it doesn't decide.** It tells you what your code requires and
|
|
28
|
+
what your config permits. You decide what to do.
|
|
29
|
+
- **Configuration is optional.** `browsable` runs with zero config.
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
Add it to your Rails app's `Gemfile`:
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
group :development, :test do
|
|
37
|
+
gem "browsable"
|
|
38
|
+
end
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Then `bundle install`. Or install it standalone:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
gem install browsable
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## System dependencies — the `doctor` workflow
|
|
48
|
+
|
|
49
|
+
`browsable` shells out to `stylelint` and `eslint` (and the `node` runtime they
|
|
50
|
+
need). Those are *not* gem dependencies — they live globally on your machine.
|
|
51
|
+
Check what you have:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
bundle exec browsable doctor
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`doctor` prints, for each missing tool, the exact command to install it. Let it
|
|
58
|
+
do the work for you:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
bundle exec browsable doctor --fix # installs missing tools via brew / npm
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
ERB and HTML analysis needs nothing extra — the `herb` gem is a dependency and
|
|
65
|
+
runs in-process.
|
|
66
|
+
|
|
67
|
+
## Quick start
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
bundle exec browsable audit
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
That's it. With no configuration, `browsable`:
|
|
74
|
+
|
|
75
|
+
1. reads `ApplicationController`'s `allow_browser` policy to learn your target,
|
|
76
|
+
2. discovers your stylesheets, views, JavaScript, and importmap pins,
|
|
77
|
+
3. audits each against that target, and
|
|
78
|
+
4. prints a report grouped by file.
|
|
79
|
+
|
|
80
|
+
## CLI reference
|
|
81
|
+
|
|
82
|
+
| Command | Purpose |
|
|
83
|
+
| --- | --- |
|
|
84
|
+
| `browsable` / `browsable audit [PATH]` | Full project audit |
|
|
85
|
+
| `browsable doctor` | Check system dependencies |
|
|
86
|
+
| `browsable doctor --fix` | Install missing dependencies (opt-in) |
|
|
87
|
+
| `browsable check FILE [FILE...]` | Audit specific files (used by editors) |
|
|
88
|
+
| `browsable target [PATH]` | Show the inferred browser-support target |
|
|
89
|
+
| `browsable init` | Generate a `.browsable.yml` (non-Rails projects) |
|
|
90
|
+
| `browsable version` | Print the version |
|
|
91
|
+
|
|
92
|
+
### Flags
|
|
93
|
+
|
|
94
|
+
| Flag | Effect |
|
|
95
|
+
| --- | --- |
|
|
96
|
+
| `--target QUERY` | Override the inferred browserslist query |
|
|
97
|
+
| `--json` | Emit findings as JSON (shortcut for `--format json`) |
|
|
98
|
+
| `--format human\|json\|github` | Choose the output formatter |
|
|
99
|
+
| `--no-build` | Scan only what is on disk (`browsable` never builds assets itself) |
|
|
100
|
+
| `--include GLOB` | Add a path glob to the audit (repeatable) |
|
|
101
|
+
| `--exclude GLOB` | Exclude a path glob (repeatable) |
|
|
102
|
+
| `--fail-on warning\|error` | Exit-code policy for CI |
|
|
103
|
+
| `--config PATH` | Override the config file location |
|
|
104
|
+
|
|
105
|
+
The `--json` output is the universal interface: the LSP server (and any future
|
|
106
|
+
MCP server) consume exactly that structure. The human and GitHub formatters are
|
|
107
|
+
just alternate presentations of the same data.
|
|
108
|
+
|
|
109
|
+
## Rails generator
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
rails g browsable:install
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
This writes a fully-commented `config/browsable.yml` — every option present,
|
|
116
|
+
commented out, set to its default. It is a self-documenting reference: uncomment
|
|
117
|
+
a line to override it. Flags: `--minimal`, `--target QUERY`, `--force`.
|
|
118
|
+
|
|
119
|
+
Non-Rails projects use `browsable init`, which writes `.browsable.yml` instead.
|
|
120
|
+
|
|
121
|
+
## Configuration
|
|
122
|
+
|
|
123
|
+
`browsable` needs no config file. When one is present it is discovered in this
|
|
124
|
+
order:
|
|
125
|
+
|
|
126
|
+
1. the path passed to `--config`
|
|
127
|
+
2. `config/browsable.yml` (preferred in Rails apps)
|
|
128
|
+
3. `.browsable.yml` in the working directory
|
|
129
|
+
|
|
130
|
+
Resolution precedence (highest wins): **CLI flags → config file → inferred Rails
|
|
131
|
+
config → gem defaults**. See the generated `config/browsable.yml` for the full,
|
|
132
|
+
commented option reference.
|
|
133
|
+
|
|
134
|
+
## How it works — the inference chain
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
ApplicationController.allow_browser → Target (browserslist query) → Analyzers
|
|
138
|
+
:modern chrome 120, safari 17.2 │
|
|
139
|
+
▼
|
|
140
|
+
config/importmap.rb ─┐ CSS → stylelint
|
|
141
|
+
app/assets/** ─┼─→ Sources ─→ files by kind ───────── ERB → Herb + BCD
|
|
142
|
+
app/views/** ─┤ HTML → Herb + BCD
|
|
143
|
+
app/javascript/** ─┘ JS → eslint
|
|
144
|
+
│
|
|
145
|
+
▼
|
|
146
|
+
Report → Formatter
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`browsable` translates between Rails-land and browserslist-land: it reads
|
|
150
|
+
`allow_browser :modern`, expands it to concrete browser versions, configures
|
|
151
|
+
stylelint/eslint with that target, and runs Herb against the bundled MDN
|
|
152
|
+
browser-compat-data snapshot for ERB/HTML.
|
|
153
|
+
|
|
154
|
+
### Partial `allow_browser` policies
|
|
155
|
+
|
|
156
|
+
If your `allow_browser` policy is a hash that pins only some browsers — say
|
|
157
|
+
`versions: { safari: 16.4, firefox: 121 }` — Rails leaves every browser you
|
|
158
|
+
*don't* list allowed at **any** version (it only blocks a browser it was given a
|
|
159
|
+
minimum, or `false`, for). browsable audits exactly the browsers you pinned and
|
|
160
|
+
prints a note naming the rest. To audit against more, set an explicit `target:`
|
|
161
|
+
in `config/browsable.yml`. The same note-and-fall-back-to-`defaults` behaviour
|
|
162
|
+
applies when browsable cannot resolve your policy statically.
|
|
163
|
+
|
|
164
|
+
### Where `defaults` comes from
|
|
165
|
+
|
|
166
|
+
When there is no `allow_browser` policy at all, browsable audits against the
|
|
167
|
+
[browserslist](https://github.com/browserslist/browserslist) `defaults` query —
|
|
168
|
+
the "reasonable broad support" baseline the wider frontend ecosystem uses. It is
|
|
169
|
+
resolved **live** from caniuse data when the `browserslist` CLI is installed
|
|
170
|
+
(`npm install -g browserslist`); otherwise browsable uses a small **built-in
|
|
171
|
+
approximation** and says so in a note. Either way these versions are *not* a
|
|
172
|
+
Rails concept — Rails blocks nothing unless you call `allow_browser` — and they
|
|
173
|
+
are not derived from stylelint or eslint. For a precise, stable target, set
|
|
174
|
+
`target:` in `config/browsable.yml`.
|
|
175
|
+
|
|
176
|
+
### Suggested `allow_browser` fix
|
|
177
|
+
|
|
178
|
+
When an audit finds errors that are purely a version conflict — your code needs
|
|
179
|
+
a browser version newer than your policy permits — browsable prints a ready-to-paste
|
|
180
|
+
`allow_browser` line that raises *only* the offending browsers to the minimum
|
|
181
|
+
those features require, leaving every other browser untouched:
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
Suggested allow_browser policy
|
|
185
|
+
allow_browser versions: { chrome: 120, edge: 120, firefox: 125, safari: 17.2, opera: 106 }
|
|
186
|
+
firefox: 121 → 125
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
It is a suggestion, not an instruction: tightening the policy is one fix, changing
|
|
190
|
+
the code (a fallback, a `@supports` rule) is another. browsable reports; you
|
|
191
|
+
decide. The suggestion is derived from HTML/ERB findings, which carry exact
|
|
192
|
+
version data; it also appears in `--json` (`suggested_policy`) and as a GitHub
|
|
193
|
+
Actions notice.
|
|
194
|
+
|
|
195
|
+
### Per-controller and per-action policies
|
|
196
|
+
|
|
197
|
+
Rails lets any controller override `allow_browser`, and scope the override to
|
|
198
|
+
certain actions with `only:`/`except:`. browsable scans every file under
|
|
199
|
+
`app/controllers/` (including `concerns/`) and lists each `allow_browser` call
|
|
200
|
+
it finds — its versions and any action scope — under **Browser policies** in the
|
|
201
|
+
report.
|
|
202
|
+
|
|
203
|
+
The audit itself runs against a single target (ApplicationController's policy,
|
|
204
|
+
or your `config/browsable.yml`). browsable does **not** try to map each frontend
|
|
205
|
+
asset to the exact endpoints — and policies — that serve it. CSS and importmap
|
|
206
|
+
JavaScript are global assets, included via layout helpers on nearly every page,
|
|
207
|
+
so they have no single owning controller action; a per-asset policy graph would
|
|
208
|
+
be guesswork. Instead, browsable shows you the whole policy landscape: if a
|
|
209
|
+
controller serves shared assets to a broader range of browsers than
|
|
210
|
+
ApplicationController, audit against that policy explicitly with `--target` or
|
|
211
|
+
`config/browsable.yml`. Per-action auditing of `app/views/<controller>/`
|
|
212
|
+
templates against their controller's policy is a planned refinement.
|
|
213
|
+
|
|
214
|
+
## Rake tasks
|
|
215
|
+
|
|
216
|
+
Inside a Rails app, the railtie registers:
|
|
217
|
+
|
|
218
|
+
- `rake browsable:audit` — audit `app/assets/builds/` as it stands
|
|
219
|
+
- `rake browsable:audit:fresh` — run `assets:precompile` first, then audit
|
|
220
|
+
- `rake browsable:doctor` — run the dependency check
|
|
221
|
+
|
|
222
|
+
`browsable` never precompiles assets on its own. In CI, compose the pipeline
|
|
223
|
+
explicitly: `bundle exec rails assets:precompile && bundle exec browsable audit`.
|
|
224
|
+
|
|
225
|
+
## Contributing
|
|
226
|
+
|
|
227
|
+
This gem lives in the `browsable/` subdirectory of the
|
|
228
|
+
[monorepo](https://github.com/romanhood/browsable). To work on it:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
cd browsable
|
|
232
|
+
bundle install
|
|
233
|
+
bundle exec rspec
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Refresh the bundled compat data with `ruby bin/update-bcd-snapshot`.
|
|
237
|
+
|
|
238
|
+
## License
|
|
239
|
+
|
|
240
|
+
MIT — see the [LICENSE](../LICENSE) at the monorepo root.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Maintenance script — refresh data/bcd-snapshot.json from the latest published
|
|
5
|
+
# @mdn/browser-compat-data. The gem ships the generated snapshot; this script
|
|
6
|
+
# is run by maintainers, never at gem runtime.
|
|
7
|
+
#
|
|
8
|
+
# ruby bin/update-bcd-snapshot
|
|
9
|
+
#
|
|
10
|
+
# It downloads the full dataset (several MB) and keeps only the subtrees
|
|
11
|
+
# browsable's ERB/HTML analyzer actually consults, so the committed file stays
|
|
12
|
+
# small.
|
|
13
|
+
|
|
14
|
+
require "net/http"
|
|
15
|
+
require "uri"
|
|
16
|
+
require "json"
|
|
17
|
+
require "time"
|
|
18
|
+
|
|
19
|
+
SOURCE = "https://cdn.jsdelivr.net/npm/@mdn/browser-compat-data/data.json"
|
|
20
|
+
OUTPUT = File.expand_path("../data/bcd-snapshot.json", __dir__)
|
|
21
|
+
|
|
22
|
+
# Only these subtrees are retained.
|
|
23
|
+
SUBTREES = [
|
|
24
|
+
%w[html elements],
|
|
25
|
+
%w[html global_attributes],
|
|
26
|
+
%w[css properties]
|
|
27
|
+
].freeze
|
|
28
|
+
|
|
29
|
+
def fetch(url, redirects: 5)
|
|
30
|
+
raise "Too many redirects" if redirects.negative?
|
|
31
|
+
|
|
32
|
+
response = Net::HTTP.get_response(URI.parse(url))
|
|
33
|
+
case response
|
|
34
|
+
when Net::HTTPSuccess then response.body
|
|
35
|
+
when Net::HTTPRedirection then fetch(response["location"], redirects: redirects - 1)
|
|
36
|
+
else raise "HTTP #{response.code} fetching #{url}"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
puts "Fetching #{SOURCE} ..."
|
|
41
|
+
full = JSON.parse(fetch(SOURCE))
|
|
42
|
+
|
|
43
|
+
snapshot = {
|
|
44
|
+
"__meta" => {
|
|
45
|
+
"source" => SOURCE,
|
|
46
|
+
"generated_at" => Time.now.utc.iso8601,
|
|
47
|
+
"subtrees" => SUBTREES.map { |path| path.join(".") }
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
SUBTREES.each do |path|
|
|
52
|
+
node = full.dig(*path)
|
|
53
|
+
unless node
|
|
54
|
+
warn " ! subtree #{path.join('.')} not found — skipping"
|
|
55
|
+
next
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Rebuild the nested structure: ["html", "elements"] => { "html" => { "elements" => node } }
|
|
59
|
+
nested = path[1..].reverse.reduce(node) { |acc, key| { key => acc } }
|
|
60
|
+
snapshot[path.first] = (snapshot[path.first] || {}).merge(nested)
|
|
61
|
+
puts " + kept #{path.join('.')} (#{node.size} entries)"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
File.write(OUTPUT, "#{JSON.pretty_generate(snapshot)}\n")
|
|
65
|
+
puts "Wrote #{OUTPUT} (#{File.size(OUTPUT)} bytes)"
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
{
|
|
2
|
+
"__meta": {
|
|
3
|
+
"source": "https://cdn.jsdelivr.net/npm/@mdn/browser-compat-data/data.json",
|
|
4
|
+
"generated_at": "2026-05-01T00:00:00Z",
|
|
5
|
+
"subtrees": ["html.elements", "html.global_attributes", "css.properties"],
|
|
6
|
+
"note": "A curated subset of MDN browser-compat-data. Regenerate with bin/update-bcd-snapshot."
|
|
7
|
+
},
|
|
8
|
+
"html": {
|
|
9
|
+
"elements": {
|
|
10
|
+
"dialog": {
|
|
11
|
+
"__compat": {
|
|
12
|
+
"mdn_url": "https://developer.mozilla.org/docs/Web/HTML/Element/dialog",
|
|
13
|
+
"status": { "baseline": "high" },
|
|
14
|
+
"support": {
|
|
15
|
+
"chrome": { "version_added": "37" },
|
|
16
|
+
"edge": { "version_added": "79" },
|
|
17
|
+
"firefox": { "version_added": "98" },
|
|
18
|
+
"safari": { "version_added": "15.4" }
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"details": {
|
|
23
|
+
"__compat": {
|
|
24
|
+
"status": { "baseline": "high" },
|
|
25
|
+
"support": {
|
|
26
|
+
"chrome": { "version_added": "12" },
|
|
27
|
+
"edge": { "version_added": "79" },
|
|
28
|
+
"firefox": { "version_added": "49" },
|
|
29
|
+
"safari": { "version_added": "6" }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"summary": {
|
|
34
|
+
"__compat": {
|
|
35
|
+
"status": { "baseline": "high" },
|
|
36
|
+
"support": {
|
|
37
|
+
"chrome": { "version_added": "12" },
|
|
38
|
+
"edge": { "version_added": "79" },
|
|
39
|
+
"firefox": { "version_added": "49" },
|
|
40
|
+
"safari": { "version_added": "6" }
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"search": {
|
|
45
|
+
"__compat": {
|
|
46
|
+
"mdn_url": "https://developer.mozilla.org/docs/Web/HTML/Element/search",
|
|
47
|
+
"status": { "baseline": "low" },
|
|
48
|
+
"support": {
|
|
49
|
+
"chrome": { "version_added": "118" },
|
|
50
|
+
"edge": { "version_added": "118" },
|
|
51
|
+
"firefox": { "version_added": "118" },
|
|
52
|
+
"safari": { "version_added": "17" }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"picture": {
|
|
57
|
+
"__compat": {
|
|
58
|
+
"status": { "baseline": "high" },
|
|
59
|
+
"support": {
|
|
60
|
+
"chrome": { "version_added": "38" },
|
|
61
|
+
"edge": { "version_added": "13" },
|
|
62
|
+
"firefox": { "version_added": "38" },
|
|
63
|
+
"safari": { "version_added": "9.1" }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"template": {
|
|
68
|
+
"__compat": {
|
|
69
|
+
"status": { "baseline": "high" },
|
|
70
|
+
"support": {
|
|
71
|
+
"chrome": { "version_added": "35" },
|
|
72
|
+
"edge": { "version_added": "13" },
|
|
73
|
+
"firefox": { "version_added": "22" },
|
|
74
|
+
"safari": { "version_added": "8" }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"slot": {
|
|
79
|
+
"__compat": {
|
|
80
|
+
"status": { "baseline": "high" },
|
|
81
|
+
"support": {
|
|
82
|
+
"chrome": { "version_added": "53" },
|
|
83
|
+
"edge": { "version_added": "79" },
|
|
84
|
+
"firefox": { "version_added": "63" },
|
|
85
|
+
"safari": { "version_added": "10.1" }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"datalist": {
|
|
90
|
+
"__compat": {
|
|
91
|
+
"status": { "baseline": "high" },
|
|
92
|
+
"support": {
|
|
93
|
+
"chrome": { "version_added": "20" },
|
|
94
|
+
"edge": { "version_added": "12" },
|
|
95
|
+
"firefox": { "version_added": "4" },
|
|
96
|
+
"safari": { "version_added": "12.1" }
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
"output": {
|
|
101
|
+
"__compat": {
|
|
102
|
+
"status": { "baseline": "high" },
|
|
103
|
+
"support": {
|
|
104
|
+
"chrome": { "version_added": "10" },
|
|
105
|
+
"edge": { "version_added": "13" },
|
|
106
|
+
"firefox": { "version_added": "6" },
|
|
107
|
+
"safari": { "version_added": "5.1" }
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"meter": {
|
|
112
|
+
"__compat": {
|
|
113
|
+
"status": { "baseline": "high" },
|
|
114
|
+
"support": {
|
|
115
|
+
"chrome": { "version_added": "8" },
|
|
116
|
+
"edge": { "version_added": "13" },
|
|
117
|
+
"firefox": { "version_added": "16" },
|
|
118
|
+
"safari": { "version_added": "6" }
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"progress": {
|
|
123
|
+
"__compat": {
|
|
124
|
+
"status": { "baseline": "high" },
|
|
125
|
+
"support": {
|
|
126
|
+
"chrome": { "version_added": "8" },
|
|
127
|
+
"edge": { "version_added": "12" },
|
|
128
|
+
"firefox": { "version_added": "6" },
|
|
129
|
+
"safari": { "version_added": "6" }
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
"canvas": {
|
|
134
|
+
"__compat": {
|
|
135
|
+
"status": { "baseline": "high" },
|
|
136
|
+
"support": {
|
|
137
|
+
"chrome": { "version_added": "4" },
|
|
138
|
+
"edge": { "version_added": "12" },
|
|
139
|
+
"firefox": { "version_added": "2" },
|
|
140
|
+
"safari": { "version_added": "3.1" }
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
"video": {
|
|
145
|
+
"__compat": {
|
|
146
|
+
"status": { "baseline": "high" },
|
|
147
|
+
"support": {
|
|
148
|
+
"chrome": { "version_added": "4" },
|
|
149
|
+
"edge": { "version_added": "12" },
|
|
150
|
+
"firefox": { "version_added": "3.5" },
|
|
151
|
+
"safari": { "version_added": "3.1" }
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"audio": {
|
|
156
|
+
"__compat": {
|
|
157
|
+
"status": { "baseline": "high" },
|
|
158
|
+
"support": {
|
|
159
|
+
"chrome": { "version_added": "4" },
|
|
160
|
+
"edge": { "version_added": "12" },
|
|
161
|
+
"firefox": { "version_added": "3.5" },
|
|
162
|
+
"safari": { "version_added": "3.1" }
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
"global_attributes": {
|
|
168
|
+
"popover": {
|
|
169
|
+
"__compat": {
|
|
170
|
+
"mdn_url": "https://developer.mozilla.org/docs/Web/HTML/Global_attributes/popover",
|
|
171
|
+
"status": { "baseline": "low" },
|
|
172
|
+
"support": {
|
|
173
|
+
"chrome": { "version_added": "114" },
|
|
174
|
+
"edge": { "version_added": "114" },
|
|
175
|
+
"firefox": { "version_added": "125" },
|
|
176
|
+
"safari": { "version_added": "17" }
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
"inert": {
|
|
181
|
+
"__compat": {
|
|
182
|
+
"status": { "baseline": "high" },
|
|
183
|
+
"support": {
|
|
184
|
+
"chrome": { "version_added": "102" },
|
|
185
|
+
"edge": { "version_added": "102" },
|
|
186
|
+
"firefox": { "version_added": "112" },
|
|
187
|
+
"safari": { "version_added": "15.5" }
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
"loading": {
|
|
192
|
+
"__compat": {
|
|
193
|
+
"status": { "baseline": "high" },
|
|
194
|
+
"support": {
|
|
195
|
+
"chrome": { "version_added": "77" },
|
|
196
|
+
"edge": { "version_added": "79" },
|
|
197
|
+
"firefox": { "version_added": "75" },
|
|
198
|
+
"safari": { "version_added": "16.4" }
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
"enterkeyhint": {
|
|
203
|
+
"__compat": {
|
|
204
|
+
"status": { "baseline": "high" },
|
|
205
|
+
"support": {
|
|
206
|
+
"chrome": { "version_added": "77" },
|
|
207
|
+
"edge": { "version_added": "79" },
|
|
208
|
+
"firefox": { "version_added": "94" },
|
|
209
|
+
"safari": { "version_added": "13.1" }
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
"autocapitalize": {
|
|
214
|
+
"__compat": {
|
|
215
|
+
"status": { "baseline": "low" },
|
|
216
|
+
"support": {
|
|
217
|
+
"chrome": { "version_added": "43" },
|
|
218
|
+
"edge": { "version_added": "79" },
|
|
219
|
+
"firefox": { "version_added": "111" },
|
|
220
|
+
"safari": { "version_added": "5" }
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
"is": {
|
|
225
|
+
"__compat": {
|
|
226
|
+
"mdn_url": "https://developer.mozilla.org/docs/Web/HTML/Global_attributes/is",
|
|
227
|
+
"status": { "baseline": false },
|
|
228
|
+
"support": {
|
|
229
|
+
"chrome": { "version_added": "67" },
|
|
230
|
+
"edge": { "version_added": "79" },
|
|
231
|
+
"firefox": { "version_added": "63" },
|
|
232
|
+
"safari": { "version_added": false }
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
"contenteditable": {
|
|
237
|
+
"__compat": {
|
|
238
|
+
"status": { "baseline": "high" },
|
|
239
|
+
"support": {
|
|
240
|
+
"chrome": { "version_added": "4" },
|
|
241
|
+
"edge": { "version_added": "12" },
|
|
242
|
+
"firefox": { "version_added": "3" },
|
|
243
|
+
"safari": { "version_added": "3.1" }
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
"hidden": {
|
|
248
|
+
"__compat": {
|
|
249
|
+
"status": { "baseline": "high" },
|
|
250
|
+
"support": {
|
|
251
|
+
"chrome": { "version_added": "6" },
|
|
252
|
+
"edge": { "version_added": "12" },
|
|
253
|
+
"firefox": { "version_added": "4" },
|
|
254
|
+
"safari": { "version_added": "5" }
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
"draggable": {
|
|
259
|
+
"__compat": {
|
|
260
|
+
"status": { "baseline": "high" },
|
|
261
|
+
"support": {
|
|
262
|
+
"chrome": { "version_added": "4" },
|
|
263
|
+
"edge": { "version_added": "12" },
|
|
264
|
+
"firefox": { "version_added": "3.5" },
|
|
265
|
+
"safari": { "version_added": "6" }
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
"css": {
|
|
272
|
+
"properties": {
|
|
273
|
+
"aspect-ratio": {
|
|
274
|
+
"__compat": {
|
|
275
|
+
"status": { "baseline": "high" },
|
|
276
|
+
"support": {
|
|
277
|
+
"chrome": { "version_added": "88" },
|
|
278
|
+
"edge": { "version_added": "88" },
|
|
279
|
+
"firefox": { "version_added": "89" },
|
|
280
|
+
"safari": { "version_added": "15" }
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
"gap": {
|
|
285
|
+
"__compat": {
|
|
286
|
+
"status": { "baseline": "high" },
|
|
287
|
+
"support": {
|
|
288
|
+
"chrome": { "version_added": "84" },
|
|
289
|
+
"edge": { "version_added": "84" },
|
|
290
|
+
"firefox": { "version_added": "63" },
|
|
291
|
+
"safari": { "version_added": "14.1" }
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
"inset": {
|
|
296
|
+
"__compat": {
|
|
297
|
+
"status": { "baseline": "high" },
|
|
298
|
+
"support": {
|
|
299
|
+
"chrome": { "version_added": "87" },
|
|
300
|
+
"edge": { "version_added": "87" },
|
|
301
|
+
"firefox": { "version_added": "66" },
|
|
302
|
+
"safari": { "version_added": "14.1" }
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
"container-type": {
|
|
307
|
+
"__compat": {
|
|
308
|
+
"status": { "baseline": "low" },
|
|
309
|
+
"support": {
|
|
310
|
+
"chrome": { "version_added": "105" },
|
|
311
|
+
"edge": { "version_added": "105" },
|
|
312
|
+
"firefox": { "version_added": "110" },
|
|
313
|
+
"safari": { "version_added": "16" }
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
"accent-color": {
|
|
318
|
+
"__compat": {
|
|
319
|
+
"status": { "baseline": "high" },
|
|
320
|
+
"support": {
|
|
321
|
+
"chrome": { "version_added": "93" },
|
|
322
|
+
"edge": { "version_added": "93" },
|
|
323
|
+
"firefox": { "version_added": "92" },
|
|
324
|
+
"safari": { "version_added": "15.4" }
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
"text-wrap": {
|
|
329
|
+
"__compat": {
|
|
330
|
+
"status": { "baseline": "low" },
|
|
331
|
+
"support": {
|
|
332
|
+
"chrome": { "version_added": "114" },
|
|
333
|
+
"edge": { "version_added": "114" },
|
|
334
|
+
"firefox": { "version_added": "121" },
|
|
335
|
+
"safari": { "version_added": "17.4" }
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|