PHP Class to Rewrite CSS3 Rules for Cross Browser Compatibility - php

I need some help writing an awesome class to take a style sheet, detect browser specific CSS3 rules, and add support for all compatible browsers. This way, we can just write our styles sheets for one browser and then process the CSS files when we are ready for production.
Here's my thoughts on the class so far:
class CssRewriter {
public function reformCss($file) {
// Get the CSS as a string
$cssString = file_get_contents($file);
// Use regex to capture all styles delimited by {...}
// Use regex to determine if the any of the captured styles are browser
// specific (starts with -moz, -webkit, etc)
// Determine which CSS3 rules are not present and add them to the style
// (so if you have -moz-linear-gradient, automatically add the webkit
// version)
}
}

Yikes. CSS parsers are not as easy as you imagine, man. Depending on regular expressions is just asking for one typo to be totally misinterpreted.
Not the answer you were looking for, but quite possibly a better one: have you considered using Sass and mixins? You're not the first to hit the issue of the repetitive nature of CSS, so someone else has already faced the challenge of a CSS pre-processor for you.

Your best bet would be to modify existing CSS parser like CSS Tidy and add in a additional logic to output backwards-compatible CSS.

Related

Dark mode without JavaScript

I have a small website using only PHP, HTML, and CSS and want to add Dark Mode on it. I've found a lot solutions, but all of them use JavaScript. Is that possible to add Dark Mode without JS?
One option could be to use a routing element in your URL that determines (using server side logic) which set of cascading style sheets gets loaded.
For example in http://foobar.com/dark/path/to/content the /dark/ part of the URL could make the server load your "dark" theme CSS files.
You already have all you need. Browser detection is done with CSS following the Media Queries Level 5 specification using a prefers-color-scheme media query for detection. If you're familiar with responsive web-design with CSS then you already have all the knowledge - the only difference is that responsive CSS is about geography (sizes, columns, padding, spacing, font-size, etc.) and prefers-color-scheme is about ... well ... color. Thomas Steiner (#DenverCoder9) has an awesome article "prefers-color-scheme: Hello darkness, my old friend" that covers this.
If you are asking about PHP specifically then you are out of luck - there is no dark mode detection methodology for server side-processing.
All efforts thus-far by the W3C (and its sponsors) has been focused on client-side / Jamstack.
There is a recommendation by Thomas Steiner (same guy) to implement a Proposed server-side client hint, but this has not been adopted (yet?) by the W3C or the browsers.
Either way - there is a significant drawback in server-side detection (both with Thomas' recommendation and my solution below) in that the server will only know about a state change (e.g. macOS "Auto" mode when night fall happens) on the next server request, or more visibly, the first load of the page.
My recommendation is to leverage CSS / client-side only on this - Thomas gives some practical guidance on two methods,
1x CSS with both color schemes supported, and
2x CSS, with one being light and the other dark. I've made a educative whitepaper applying some of these methods with the CSS framework Bootstrap at vinorodrigues/bootstrap-dark to show how easy that can be - without server-side processing.
Having said that - if you must insist on PHP or server-side detection there is no workaround - but one must use some JS. The most efficient way is to leverage the js-cookie/js-cookie project, and include the following code into your HTML pages:
<script src="https://cdn.jsdelivr.net/npm/js-cookie/dist/js.cookie.min.js"></script>
<script>
// code to set the `color_scheme` cookie
var $color_scheme = Cookies.get("color_scheme");
function get_color_scheme() {
return (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) ? "dark" : "light";
}
function update_color_scheme() {
Cookies.set("color_scheme", get_color_scheme());
}
// read & compare cookie `color-scheme`
if ((typeof $color_scheme === "undefined") || (get_color_scheme() != $color_scheme))
update_color_scheme();
// detect changes and change the cookie
if (window.matchMedia)
window.matchMedia("(prefers-color-scheme: dark)").addListener( update_color_scheme );
</script>
And then your PHP will detect this cookie like this:
$color_scheme = isset($_COOKIE["color_scheme"]) ? $_COOKIE["color_scheme"] : false;
if ($color_scheme === false) $color_scheme = 'light'; // fallback
Which you can use to load the CSS:
// Load the CSS for the correct color-scheme
if ($color_scheme == 'dark') {
?><link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/vinorodrigues/bootstrap-dark#0.0/dist/bootstrap-night.min.css"><?php
} else {
?><link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0.css/bootstrap.css"><?php
}
Or, like this:
?>You are in <?= $color_scheme ?> mode.<?php
You can do a clone of the css and change the background-color, buttons... It's not really necessary really to use JavaScript
If you want to do just a button for change the css, i don't really know how to do it, but if you want to do another webpage but just for Dark Mode, just put the clone off the css that you created.

PHP - Dynamically creating a svg with embedded fonts

I want to dynamically create an svg that I can use in an <img/> tag. This in itself is easy; create an svg, set the header and echo the generated parts in their correct place.
The problem is, I want to be able to embed fonts in the svg.
I've tried using the #font-face rule in the css of the svg, but that didn't work (MDN says that it only works on Android and Safari).
Is there any cross-browser way to do this?
Solutions I've Considered:
Possible Solution #01:
The solution:
In my main file, create an svg file which uses the #font-face css rule, and then use exec() to use inkscape to convert that svg into another svg, which converts all letters into paths. I then could use echo file_get_contents($inkscape_file) with the correct headers to output it as a svg which can be used with an <img/> tag.
The problem with this:
This creates 2 additional files, so seems very inefficient. Furthermore, since each user will end up generating several images, the space it takes up would grow phenomenally.
Possible Solution #02:
The solution:
Make a template in illustrator, then save it as svg, and tick the embed all glyphs option. Then replace the text & the styles with the options from the PHP script. Use the correct header and output this.
The problem with this:
This severely limits the amount of fonts that can be used, as it is limited to only those which I create a template for. My desired behaviour was to add the option for users to upload their own fonts and use them. This solution does not allow for that.
Additional information that may be of some relevance:
My development server runs fedora, and the production server uses redhat.
The #font-face rule I am currently using is as follows:
#font-face {
font-family: Potato;
src: url("/fonts/potato.otf");
}
You can't load any external resources declared in the svg from the <img> tag.
The only solutions would be some crappy ways to append the glyphs or the fonts into the svg file itself.
Actually there is a not so crappy way to do it as you found in this answer by lèse-majesté.
The best way is then still IMO to not use an <img> tag to display the svg documents, but rather use an <iframe> or an <object> tag, with the #font-face declared inside the svg file, or even directly include an inline version into the document. These methods do allow the loading of external resources such as fonts.
Then you just have to save the fonts on your server or just an url to the font in the #font-face declaration.

configure htmlpurifier with html5 and css3

I am using htmlpurifier. I have some doubts which are as below.
1- My config file contain
$config->set('HTML.Trusted' ,true);
$config->set('CSS.Trusted', true);
But a simple Google is landing me to pages where there are recommendation not to use *.Trusted as "true".
I am not able to understand why should we should not set *.Trusted to true? Can you please explain me. Because if I remove it than I wont get inline css? Even CSS.AllowTricky is not helping.
2- I found that HTML5 and CSS3 selectors are not allowed.
like the code at htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php
// - No Unicode support
// - No escapes support
// - No string support (by proxy no attrib support)
// - element_name is matched against allowed
// elements (some people might find this
// annoying...)
// - Pseudo-elements one of :first-child, :link,
// :visited, :active, :hover, :focus
// handle ruleset
$selectors = array_map('trim', explode(',', $selector));
$new_selectors = array();
foreach ($selectors as $sel) {
//some code to filter css selectors
}
do not contain any code which can allow selectors like '[class*="grid-"]'. Hence all such css is getting removed after purification. Is ther some way to allow all CSS3?
3- Is there some way to allow all HTML 5 tags? for example if we have html like
<section class="mainhead">
<div class="subhead"> </div> </section>
then purifier removes and due to which some css like
.mainhead .subhead { //some css}
wont work.
Setting HTML.Trusted to true enables unsafe elements, such as script and forms. If you, for example, want to allow forms, but don't want to allow scripts, just add them to HTML.ForbiddenElements:
$config->set('HTML.Trusted', true);
$config->set('HTML.ForbiddenElements', ['script']);
CSS3 selectors are not supported - there is a pending Pull Request, but it has been inactive for more than a year (as of Aug 2019). I don't think this will change any soon.
As for HTML5 support - you can use an extension package https://github.com/xemlock/htmlpurifier-html5 (which I'm the author of), which adds spec compliant definitions of HTML5 elements. It's usage is almost the same the bare HTML Purifier - you just have to replace HTMLPurifier_Config with HTMLPurifier_HTML5Config.

htmlpurifier removes all the formatting done by CKEDitor

I am using CKEditor to let the user post their comments. I thought to use the htmlpurifier to secure my html. But when I tried it, it actually removes all the formatting done by CKEditor.
The CKEditor generated the following html
<div class="originalpost"><span style="color:#B22222;">
<em><u><strong><span style="font-size:250%;">
This is Pakistan</span></strong></u></em></span></div>
After purifying with htmlpurifier the html became like this
<div class=""originalpost""><span><em><u><strong>
<span>This is Pakistan</span></strong></u></em></span></div>
It actually removes all the inline css styles and also class=""originalpost"" is not understand able.
I have used the following way to purify the html with htmlpurifier
require_once("path\HTMLPurifier.auto.php");
$config = HTMLPurifier_Config::createDefault();
$purifier = new HTMLPurifier($config);
$html = "xyzhtml";
$clean_html = $purifier->purify($html);
I want to keep the user formatting, How can I configure htmlpurifier to keep the user formatting also don't change the inline css.
It actually removes all the inline css styles
Inline styles are indeed dangerous - JavaScript can be injected into them using url(), IE's dodgy expression() and browser-specific behavioural extensions.
HTMLPurifier can parse inline styles and filter the dangerous properties and values. You can turn this on by including style in your whitelisted attributes.
$config->set('HTML.AllowedAttributes', '*.style, ...');
style is not included in the default attribute list because parsing styles is a lot of extra complexity (with accompanying chance of bugs) and most applications don't need it.
You can configure the properties that are permitted using %CSS.AllowedProperties if you wish.
I can't reproduce the " problem but certainly ensuring PHP's magic_quotes_gpc option is turned off is an all-round good thing...
I bet that you need to turn off Sybase quotes.

Using Javascript and PHP to generate images using a TTF

I am having trouble using a script I found at http://www.marcofolio.net/webdesign/use_a_custom_font_on_your_website.html
The problem is, when I load a page, the text shows up then each word is replaced by a generated image of it using the PHP GD lib.
It creates a flicker effect that I can't seem to get rid of. There are options is the js file:
var hideFlicker = true;
var hideFlickerCSS = "replacement-screen.css";
var hideFlickerTimeout = 0;
But when I change any of those settings, nothing happens.
Please help!
Thank you.
For what you seem to be trying to do, image replacement is an extremely outdated method. All the ninja-devs are using technology called #font-face for their fonts and font replacements.
It's simpler, doesn't require anything to happen on the server and text on the page can be modified dynamically.
You can use services like http://www.fontsquirrel.com/ or http://code.google.com/webfonts for ready made font packages.
If you have a custom font (that you have a license for) you can create an #font-face package for it, using fontsquirrel's #font-face generator: http://www.fontsquirrel.com/fontface/generator
And then you just define your fonts in the CSS. Simple, elegant and works in 99% of browsers (yes, even IE6)
Cheers!

Categories