I'm building a mobile app with 2D & 3D elements.
2D elements use React, and I'm using create-react-app for the build/bundling etc.
3D elements use A-Frame.
For iOS, I need to obtain device orientation permissions, and I'm doing this using the standard A-Frame component: https://aframe.io/docs/1.3.0/components/device-orientation-permission-ui.html
However I want to change the appearance of the modal, by specifying my own CSS (as suggested on that page).
I have a problem that appears only in my production build.
I've written the CSS overrides that I want in my App.css. I build my production JS and CSS files.
They are included in index.html like this (inside the <head>
)
<script defer="defer" src="/static/js/main.6b739253.js"></script>
<link href="/static/css/main.8198a130.css" rel="stylesheet">
However, on initialization, A-Frame adds its own CSS files to the end of the HTML header:
<style type="text/css" data-href="src/style/aframe.css">
...CSS here...
</style>
Because the A-Frame CSS appears at the end of the HTML header, it takes priority over my custom CSS, and I end up with the A-Frame styling for the modal, rather than my custom styling.
I've come up with a solution for this, but I think there's got to be a better one...
My solution: the following code at the top of my top-level React component, which explicitly removes the aframe.css styles from the HTML (I've also added the A-Frame styles that I don't want to override directly in my App.css, where I can have full control over what I do & don't include).
useEffect(() => {
var head = document.getElementsByTagName('HEAD')[0];
for (var ii = 0; ii < head.children.length; ii++) {
const child = head.children[ii];
if (child.attributes['data-href'] &&
child.attributes['data-href'].nodeValue === "src/style/aframe.css") {
head.removeChild(child);
}
}
}, [])
I'm looking for a better solution, where I don't have to duplicate large chunks of aframe.css in my own CSS file, and I can simply have the two CSS files loaded, but prioritized in a different order.
Ideally that solution would not require me to eject from create-react-app, which I have managed to avoid needing to do so far.
There is in fact a simple solution here.
A CSS specifier that specifies an element selector + a class selector is more specific than a specifier that specifies a class selector only.
https://www.w3schools.com/css/css_specificity.asp
So the following CSS...
button.a-dialog-allow-button {
background-color: red;
}
will be more specific (and hence take precedence over) the A-Frame defaults which look like this:
.a-dialog-allow-button {
background-color: #00ceff;
}
Similarly you can override .a-modal
with div.a-modal
, .a-dialog
with div.a-dialog
etc.
One thing to watch out for (this threw me when testing this)... Not all A-Frame modals use the a-modal
and a-dialog
classes.
There are various other classes, used for specific modals - e.g. a-enter-vr-modal
and a-orientation-modal
(used for portrait / landscape orientation, rather than for device orientation permisions).
So just if you see an A-Frame modal, and your changes don't seem to have worked, it may be because it is using a different set of modal classes from the ones you changed. Check the class names carefully!