I have a site using Bootstrap 5 that includes the following input tag:
<input class="form-check-input ms-1" id="validated" name="validated" type="checkbox" checked>
The inclusion of the form-check-input class causes the client to generate the error message:
Refused to load the image 'data:image/svg+xml,%3csvg
xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath
fill='none' stroke='%23fff' stroke-linecap='round'
stroke-linejoin='round' stroke-width='3' d='M6 10l3
3l6-6'/%3e%3c/svg%3e' because it violates the following Content
Security Policy directive: "img-src 'self' www.w3.org".
Can someone please lend me a clue as to why this is being blocked? I have tried all the permutations of data://www.w3.org, http://www.w3.org, *.w3.org, etc., in the CSP and none seem to satisfy the client.
This happens identically with a Chrome and Edge client.
You can also extract the SVGs into separate files using Webpack. For example, see the official documentation at https://getbootstrap.com/docs/5.2/getting-started/webpack/#extracting-svg-files
modules.exports = {
...,
module: {
rules: [
{
mimetype: 'image/svg+xml',
scheme: 'data',
type: 'asset/resource',
generator: {
filename: 'icons/[hash].svg'
}
}
]
}
};
Bootstrap CSS stylesheet contains .form-check-input class with data:-Url images:
.form-check-input:checked[type=checkbox] {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e");
}
.form-check-input:checked[type=radio] {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e");
}
.form-check-input[type=checkbox]:indeterminate {
background-color: #0d6efd;
border-color: #0d6efd;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e");
}
To allow these images you have to add data: scheme-source into img-src directive.
Related
I have made a single contour .svg cursor (basically a triangle curved at the bottom) without any fill, and I want to be able to change its fill color. I can't just make few different svgs for this, due to fill color being picked by user.
QtGraphicalEffects library is not supported since Qt6, so all I could find on this topic was of little use. The solution for this might be to just drop my svg over a colored rectangle, but then I'll have to mask out the area outside of my cursor to make it transparent(or vice-versa), and I'm not sure if it's even possible. I also found some shader-based solutions but none of then seem to work for my case (might just be me being new to QML)
SVG:
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600" viewBox="0 0 600 600">
<defs>
<style>
.cls-1 {
fill: none;
stroke: #414141;
stroke-width: 44px;
fill-rule: evenodd;
}
</style>
</defs>
<path id="Pointer_1" data-name="Pointer 1" class="cls-1" d="M300.291,48.248L556.347,560.4s-127.234-47.825-255.133-47.825c-128.157,0-256.979,47.825-256.979,47.825Z"/>
</svg>
[MULTIPLE EDITS]
Firstly, the latest builds of Qt6 do support QtGraphicalEffects via Qt5Compat.GraphicalEffects. https://doc.qt.io/qt-6/qtgraphicaleffects5-
The approach I prefer to use is to leverage the fact that most components have an icon property which has a built-in mechanism for recoloring an SVG. You set the following properties:
icon.source
icon.width
icon.height
icon.color
By creating two SVGs we can use the above approach to control the fill and stroke independently.
The typical component I use is Button, but, I strip off the default Button UI/UX and just leverage from the icon property as follows:
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Page {
SplitView {
anchors.fill: parent
orientation: Qt.Horizontal
Item {
SplitView.preferredWidth: parent.width / 2
SplitView.fillHeight: true
Item {
anchors.centerIn: parent
width: parent.width * 8 / 10
height: parent.height * 8 / 10
Button {
anchors.centerIn: parent
visible: fillCombo.currentText !== 'none'
background: Item { }
icon.source: "shape-fill.svg"
icon.width: Math.min(parent.width, parent.height)
icon.height: icon.width
icon.color: fillCombo.currentText
}
Button {
anchors.centerIn: parent
visible: strokeCombo.currentText !== 'none'
background: Item { }
icon.source: "shape-outline.svg"
icon.width: Math.min(parent.width, parent.height)
icon.height: icon.width
icon.color: strokeCombo.currentText
}
}
}
Item {
SplitView.fillWidth: true
SplitView.fillHeight: true
ColumnLayout {
anchors.centerIn: parent
Label {
text: qsTr("Stroke")
}
ComboBox {
id: strokeCombo
model: [ "lightsteelblue", "red", "orange", "yellow", "green", "blue" ]
}
Label {
Layout.topMargin: 20
text: qsTr("Fill")
}
ComboBox {
id: fillCombo
model: [ "none", "red", "orange", "yellow", "green", "blue" ]
}
}
}
}
}
// shape-outline.svg
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600" viewBox="0 0 600 600">
<path stroke="red" stroke-width="44" fill="none" d="M300.291,48.248L556.347,560.4s-127.234-47.825-255.133-47.825c-128.157,0-256.979,47.825-256.979,47.825Z"/>
</svg>
// shape-fill.svg
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600" viewBox="0 0 600 600">
<path stroke="none" fill="black" d="M300.291,48.248L556.347,560.4s-127.234-47.825-255.133-47.825c-128.157,0-256.979,47.825-256.979,47.825Z"/>
</svg>
You can Try it Online!
Alternatively, another approach is you can build your SVG as a data uri by adding a "data:image/svg+xml," prefix to your SVG string. Because you're using a data uri, you can make a function that generates the SVG based on use input:
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Page {
SplitView {
anchors.fill: parent
orientation: Qt.Horizontal
Item {
SplitView.preferredWidth: parent.width / 2
SplitView.fillHeight: true
Image {
anchors.centerIn: parent
width: parent.width * 8 / 10
height: parent.height * 8 / 10
source: todatauri(getsvg(strokeCombo.currentText, fillCombo.currentText))
fillMode: Image.PreserveAspectFit
}
}
Item {
SplitView.fillWidth: true
SplitView.fillHeight: true
ColumnLayout {
anchors.centerIn: parent
Label {
text: qsTr("Stroke")
}
ComboBox {
id: strokeCombo
model: [ "black", "red", "orange", "yellow", "green", "blue" ]
}
Label {
Layout.topMargin: 20
text: qsTr("Fill")
}
ComboBox {
id: fillCombo
model: [ "none", "red", "orange", "yellow", "green", "blue" ]
}
}
}
}
function todatauri(svg) {
return "data:image/svg+xml," + svg;
}
function getsvg(stroke, fill) {
return `<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600" viewBox="0 0 600 600">
<defs>
<style>
.cls-1 {
fill: none;
stroke: #414141;
stroke-width: 44px;
fill-rule: evenodd;
}
</style>
</defs>
<path id="Pointer_1" data-name="Pointer 1" class="cls-1" stroke="${stroke}" stroke-width="44" fill="${fill}" d="M300.291,48.248L556.347,560.4s-127.234-47.825-255.133-47.825c-128.157,0-256.979,47.825-256.979,47.825Z"/>
</svg>
`;
}
}
You can Try it Online!
I am trying to import a local SVG file in React but I keep coming across this error:
My code looks like this:
import React from "react";
import styled from "styled-components";
import { ReactComponent as Logo } from "./images/logo.svg";
const MainImage = styled.div`
height: 400px;
width: 100%;
background: #026857;
`;
const Home = () => {
return (
<div className="home">
<MainImage>
<Logo />
</MainImage>
</div>
);
};
export default Home;
I have tried many solutions offered by others such as importing default as Logo, creating an image prop to contain the local svg (<img src={'./images/logo.svg'}/> ) but none have given me any success so far. I believe I may have to add something to my Webpack config file but I'm not sure what it is and where I should put it, as the config file is nearly 800 lines of code.
Also, I am using SVG files from https://undraw.co/ if the information helps, it seems their illustrations have many tags in them which I have not seen in simple SVG icons.
<svg
id="f6dc6f51-58d1-4328-a543-5a2c5176acea"
dataName="Layer 1"
xmlns="http://www.w3.org/2000/svg"
width="922.18516"
height="747.35665"
viewBox="0 0 922.18516 747.35665"
>
<path
d="M420.91148,313.56734c-2.67984,100.75634,131.62869,203.61052,299.27661,203.61052S1154.817,318.5411,1028.01831,313.56734c-244.32514-9.5838-328.052-110.77046-303.55341-182.5C768.33985,2.60566,426.18809,115.17786,420.91148,313.56734Z"
transform="translate(-138.90742 -76.32167)"
fill="#3f3d56"
/>
<polygon
points="505.004 157.445 502.96 156.144 504.261 154.1 503.703 153.746 502.403 155.79 500.359 154.489 500.004 155.046 502.048 156.347 500.747 158.391 501.305 158.746 502.605 156.702 504.649 158.002 505.004 157.445"
fill="#fcce33"
/>
<polygon
points="657.004 305.445 654.96 304.144 656.261 302.1 655.703 301.746 654.403 303.79 652.359 302.489 652.004 303.046 654.048 304.347 652.747 306.391 653.305 306.746 654.605 304.702 656.649 306.002 657.004 305.445"
fill="#fcce33"
/>
...
assuming you are using Webpack 5, you need to configure your webpack loader to something like this using asset modules:
module: {
rules: [
{
test: /\.svg$/i,
type: 'asset/resource',
},
...
]
}
if you are using webpack 4, you can use file-loader instead of asset/resource:
module: {
rules: [
{
test: /\.svg$/i,
use: [
{
loader: 'file-loader',
},
],
},
...
]
}
then you can import your svg file like this:
import Logo from "./images/logo.svg";
//...
return <img src={Logo} />
I usually always convert each SVG into its own component like so
import * as React from "react";
const ArrowDownSVG = (props: React.SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
strokeWidth={2}
stroke="currentColor"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
viewBox="0 0 24 24"
{...props}
>
<path stroke="none" d="M0 0h24v24H0z" />
<path d="M6 9l6 6 6-6" />
</svg>
);
export default ArrowDownSVG;
Has worked for me in the past year or so
By leaving out the type for the props, you can use this in plain JS as well
Be forgiving, I am new to css let alone fontawesome :-)
I wanted to have a nice set of rating stars 0-5 and I managed it sort of using 4.7
https://jsfiddle.net/BoxRec/p3zgeLbt/36
content: "\f005\f006\f006\f006\f006";
However I needed half stars to complete the look and this required going to fontawesome 5
https://jsfiddle.net/BoxRec/p3zgeLbt/38
content: "\f005\f089\f006\f006\f006";
So I used the 5 library and now I now have the half star \f5c0 but the full star \f005 renders the same as the empty star \f006
https://jsfiddle.net/BoxRec/p3zgeLbt/46/
content: "\f005\f5c0\f006\f006\f006";
If you go to the cheatsheet, you can see that \f006 is gone in FontAwesome 5. I would (not a css guy) just use before and after tags to make the same effect. Regular vs solid is just changing the font weight.
note that I changed the font-family to 'Font Awesome\ 5 Free'
i.star {
font-family: 'Font Awesome\ 5 Free';
font-size: 16px;
color: #ffaa00;
font-style: normal;
}
i.s1::before {
content: "\f005";
font-weight: 900;
}
i.s1::after {
content: "\f005\f005\f005\f005";
font-weight: 200;
}
i.s1-5::before {
content: "\f005\f5c0";
font-weight: 900;
}
i.s1-5::after {
content: "\f005\f005\f005";
font-weight: 200;
}
Had to add this to the HTML:
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.12.0/css/all.css">
For the life of me, I cannot get my Chrome extension to display an iframe with a remote URL.
I see the following message in the console -
Refused to frame 'https://www.example.com/' because it violates the following Content Security Policy directive: "child-src 'self'". Note that 'frame-src' was not explicitly set, so 'child-src' is used as a fallback.
I found a solution on here (Injecting iframe into page with restrictive Content Security Policy), which requires injecting a local iframe which then comatins another iframe that references the remote url. This is supposed to bypass the sontent security policy. But for some reason, it does not seem to work in my case. Am I missing something or has the chrome security policy changed?
Below are portions of my extension that pertain to this issue. Note - this code is not the prettiest as I've been hacking around trying to get this to work.
The way this works right now is background.js sends a message to inject.js. inject.js inserts the first iframe, referencing the local file infobar.html. This page is our main user interface, we want the remote html page displayed in an iframe as part of this page. Then infobar.js inserts an iframe referencing the local file frame.html. Finally, frame.html has an iframe hard coded to our remote url.
Based on the previous answer, only the first iframe should have been subject to the content security policy. However, that doesn't seem to be the case here, as the one referencing example.com is actually 3 iframes deep.
manifest.json
{
...
"content_security_policy": "script-src 'self'; object-src 'self'; frame-src https://www.example.com; child-src https://www.example.com",
"background": {
"scripts": [
"js/jquery/jquery.min.js",
"src/bg/background.min.js"
],
"persistent": true
},
...
"content_scripts": [
{
...
"css": [
...
"src/inject/inject.min.css"
],
"js": [
...
"src/inject/inject.min.js"
]
}
],
"externally_connectable": {
"matches": [
"*://localhost/*",
"*://*.example.com/*
]
},
"web_accessible_resources": [
"src/inject/inject.html",
"src/inject/infobar.html",
"src/inject/infobar.min.js",
"src/inject/frame.html"
],
"sandbox": {
"pages": [
"src/inject/infobar.html",
"src/inject/frame.html"
]
}
}
inject.js
var iframe = document.createElement("iframe");
iframe.scrolling = "no";
iframe.style.cssText = "display:none;";
...
$(iframe).load(function () {
var message = {
command: "render-frame",
context: data,
frameUrl: chrome.runtime.getURL("src/inject/frame.html")
};
iframe.contentWindow.postMessage(message, '*');
iframe.style.cssText = "border: 0px; overflow: visible; padding: 0px; right: auto; width: 100%; height: " + toolbarHeight + "px; top: 0px; left: 0px; z-index: 2147483647; box-shadow: rgba(0, 0, 0, 0.498039) 0px 3px 10px; position: fixed; display: none;";
});
...
iframe.src = chrome.runtime.getURL("src/inject/infobar.html");
...
document.documentElement.appendChild(iframe);
infobar.html
Simple HTML page. Nothing pertinent in there. References infobar.js.
infobar.js
window.addEventListener("message", function (event) {
var command = event.data.command;
switch (command) {
case "render-frame":
var frame = document.createElement("iframe");
frame.scrolling = "no";
frame.src = event.data.frameUrl;
document.getElementById("content").appendChild(frame);
...
break;
}
});
frame.html
<html>
<head>
<style>
html, body, iframe, h2 {
margin: 0;
border: 0;
padding: 0;
display: block;
width: 100vw;
height: 100vh;
background: white;
color: black;
}
</style>
</head>
<body>
<iframe src="https://www.example.com/page.html"></iframe>
</body>
</html>
The proper way is to use the chrome.webRequest API in your background script and intercept HTTP responses.
You can then override response headers to modify Content-Security-Policy header. You can also modify X-Frame-Options header (if required).
Documentation: chrome.webRequest
We have a Singe Page Application using AngularJS 1.5 and it works smoothly using Chrome but unfortunately we also support IE 11+ and probably Edge and using these browsers, the performance is close to horrible (more than two seconds delay). It seems that it has something to do with the way we are using css sprites because if I remove the background-image property everything works smoothly again. My experience on css is not very high thus I hope that somebody with a deeper insight has a hint about performance optimizations. The sprite svg file (325KB 2350px x 2340px) looks like this
<?xml version="1.0" encoding="utf-8"?>
<!-- SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 2350 2340" enable-background="new 0 0 2350 2340" xml:space="preserve">
<symbol id="ic_x5F_website_x5F_blk" viewBox="0 -50 50 50">
...
<use xlink:href="#ic_x5F_website_x5F_blk" width="50" height="50" id="XMLID_496_" x="0" y="-50" transform="matrix(1 0 0 -1 284.9999 155)" overflow="visible"/>
...
</svg>
And the relevant css/ less styles are
.ico() {
&:extend(.ic-mixin);
}
.ic {
.ic-mixin;
}
.ic-mixin {
background-image: url('../icons/spritesheet.svg');
background-size: #spritesheet-width #spritesheet-height;
display: inline-block;
width: 50px;
height: 50px;
}
.icon(#column, #row, #color: blk, #offset: 0px, #offsetY: #offset) {
.createIcon(#column, #row, #color, #offset, #offsetY);
}
.createIcon(#column, #row, #color, #offsetX: 0, #offsetY: #offsetX) {
#positionX: #initIconGapX + #iconColumnWidth * (#column - 1);
#positionY: #initIconGapY + #iconOuterSize * (#row - 1);
& when (#color = wht) {
background-position: -(#positionX + #iconOuterSize + #offsetX) -(#positionY + #offsetY);
}
& when (#color = blu) {
background-position: -(#positionX + #iconOuterSize * 2 + #offsetX) -(#positionY + #offsetY);
}
}
.icon-virtual {
&:after {
.ico();
.icon(4, 23, wht, 15px);
content: ' ';
width: 20px;
height: 20px;
background-color: #green;
position: absolute;
top: 2px;
right: 2px;
}
}
Why is Chrome so much faster? Is this a cache problem? Is IE trying to fetch the huge file over and over again? Could there be a problem with the svg file itself? Or is the css to complicated? Are we missing some important properties? Is IE too slow finding the correct background position?
Thanks a lot for any hint!
UPDATE
Exchanging the big file with a different much smaller svg does not help in improving the performance.