TYPO3 - overwrite styles on a single page - css

How to overwrite some styles on a specified site?
I would like to do it the css-file way.
Still no answer below works in my case..

Depending on the amount of CSS to apply, you could also consider to just add the page ID as a class on the <body>, e.g. <body class="uid-456">:
page.bodyTag >
page.bodyTagCObject = TEXT
page.bodyTagCObject {
field = uid
wrap = <body class="uid-|">
}
Then, in your CSS:
.uid-456 myElement {
myCustomStyle... /* Applies to page ID = 456 only. */
}
UPDATE
Tested with Templavoilà. The following worked (From the Setup field of the main template):
page = PAGE
page {
typeNum = 0
10 = USER
10.userFunc = tx_templavoila_pi1->main_page
bodyTag >
bodyTagCObject = TEXT
bodyTagCObject {
field = uid
wrap = <body class="uid-|">
}
...
}

Use TypoScript to add CSS rules (using page.cssInline) or additional CSS files (page.includeCSS). See TSref, chapter for PAGE.

I recommend using Typoscript Conditions to add/overwrite (css)files.
eg.
page.headerData.10 = TEXT
page.headerData.10.value (
<link rel="stylesheet" href="fileadmin/js_css/style.css" />
)
#### add css to Page ID 1
[globalVar = TSFE:id = 1]
page.headerData.20 = TEXT
page.headerData.20.value (
<link rel="stylesheet" href="fileadmin/js_css/mycustomstyle.css" />
)
[end]
or a dirty but useful way to do so in backend is this little snippet. It uses the abtract field in your page properties where you can add some code into your <head>.
page.headerData.20 = TEXT
page.headerData.20.data = field:abstract
page.headerData.20.wrap = |

Related

Modify HTML tag from dangerouslySetInnerHTML in React

I am building a Gatsby Blog using React/Gatsby & the Wordpress API.
I render an excerpt of the latest articles on the landing page like so:
<span
className="mb-0"
id="excerpt-wrapper"
dangerouslySetInnerHTML={{ __html: this.props.post.node.excerpt}
/>
The problem is, my this.props.post.node.excerpt comes with an unwanted wrapping <p> tag. This tag inherit from Bootstrap CSS as I am using Bootstrap 4 in my whole project, and from the user agent stylesheet.
Hence I need to find a way either to :
get rid of the wrapping p tag
modify the CSS once the excerpt is mounted
I tried the following solution:
componentDidMount() {
this.removePTagMargin();
}
removePTagMargin = () => {
const excerptWrapper = document.querySelector("#excerpt-wrapper");
excerptWrapper.firstChild.style.marginBottom = "0px !important"
excerptWrapper.firstChild.style.marginBlockEnd = "0px !important"
}
but it does not work (maybe because it executes before the WP API call is done ?).
How can I solve my problem ?
This is assuming the excerpt comes from gatsby-transformer-remark.
You can choose the format of your excerpt in your GraphQL query for the post, it looks like the format you're using is HTML, you want PLAIN:
https://www.gatsbyjs.org/packages/gatsby-transformer-remark/#format
Try modifying your query by putting the format parameter on the excerpt field:
{
allMarkdownRemark {
edges {
node {
excerpt(format: PLAIN)
}
}
}
}
Edit: Hacky way of removing the <p> tags due to the inefficiencies in this gatsby-source-wordpress plugin.
Add a helper called removeParagraphTags this will simply trim the first three chars from the string and the last 4 chars from the string.
removeParagraphTags (excerpt) {
return excerpt.substr(3, excerpt.length - 7)
}
Then you can use this helper when setting the excerpt HTML.
dangerouslySetInnerHTML={{
__html: this.removeParagraphTags(this.props.post.node.excerpt)
}}

Webfundamentals, CustomElement with shadowDOM and HTML Templates with HTML import

I have various questions about the webfundamentals implementations, i have read that a true web component must have shadowDOM for css encapsulation, customElements for the logic of the component which i really love, and HTML Temapltes and import, so im trying to do it all in a customElement component and i have encounter with many and many issues that i find really hard to debug, i will enlist them all.
Does i have to insert html template into the document to actually get it? cant i get its content from js only? and in case i have to, when i intent to replace a shadowHost content hows is it works, i mean i got the template (the link) inside the shadowRoot, my actuall problem is that when i do querySelector(link[rel="import"]).import.querySelector("template") its null after the .import function tag and when i insert that function into the document, it actually gets the template content, heres the doc.
Watching that screenshot i got 2 more questions
Should i use shadowHost.innerHTML = file.querySelector(link[rel="import"]).import.querySelector("template")
to use the tag and copy its content inside the shadowRoot element? i mean how can i implement that approach? im using Angular as first example, they use an HTML file (which im guessing its a template or slots tag) and then they add it into the component as parameters on the constructor, so how with HTMLTemplates and HTMLImport i can implement that behaviour, i have used the documented functions but it doesnt works in the final phase.
Should i keep <link rel="import"> inside the shadowRoot or inside the document.head? can i implement the template without the need of adding it into the document?
I have been trying for days to do a simple customElement with shadowDOM that works completly fine, the problem is when i try to add an external to make it more robust.
Any helps? suggestions? i can show some functions that i use on the components to have an idea.
class EgHeader extends HTMLElement {
constructor() {
super();
this.shadowHost = shadowHost.bind(this);
this.shadowStyle = shadowStyle.bind(this);
this.shadowTemplate = shadowTemplate.bind(this);
this.host = this.shadowHost();
}
connectedCallback() {
this.defaultProperties();
let importSelector = this.host.querySelector(`link[rel="import"]`);
console.log(importSelector);
// this.host.appendChild(importSelector.cloneNode(true));
this.host.innerHTML = importSelector.import.querySelector(
"template"
).content;
}
defaultProperties() {
this.getAttributeNames().forEach(key => {
console.log(key);
if (key === "css") {
return this.shadowStyle(this.getAttribute(key));
}
if (key === "template") {
return this.shadowTemplate(this.getAttribute(key));
}
});
}
}
customElements.define("eg-header", EgHeader);
function shadowHost() {
let root = this.attachShadow({
mode: "open"
});
return root;
}
function shadowStyle(stylesheet) {
let link = document.createElement("link");
link.rel = "stylesheet";
link.href = stylesheet + ".css";
this.host.appendChild(link.cloneNode(true));
return link;
}
function shadowTemplate(link) {
var template = document.createElement("link");
template.rel = "import";
template.id = `${link}-template`;
template.href = link + ".html";
document.head.appendChild(template);
this.host.appendChild(template);
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="./Header.js"></script>
<script src="./index.js"></script>
</head>
<body>
<eg-header css="./Header" template="./Header">
</eg-header>
</body>
</html>
// Separated file called Header.html
<template>
<nav>This is X element</nav>
<script>
console.warn("Executed when the template is activated.");
</script>
</template>
i have read that a true web component must have shadowDOM for css encapsulation, customElements for the logic of the component which i really love, and HTML Temapltes and import
What you've read is quite outdated:
HTML Imports are deprecated so you should use another method to load templates.
Because of #1, HTML templates (aka <template> elements) are often replaced par template literals.
Templates literals can be define in Javascript. This way they can be defined in a classical Javascript file or in the ES6 module.
By the way, if you still want to use HTML Imports (not recommanded) , you'll need to use a polyfill.
<link rel="import"> should be put in the <head> element of the main document, not in the Shadow DOM.
If you want to use <template> you don't need to append it to the main document.
var template = document.createElement( 'template' )
template.innerHTML = `
<h1>Title</h1>
<div>Content</div>
`
...
this.shadowRoot.appendChild( template.content.clone( true ) )

How to check if style ID contains certain css selectors?

I have the following code in a php file used for theme options:
<style type="text/css" id="compiled_styles">
menu {color: red;}
</style>
How to check if the style with the ID "compiled_styles" contains certain css selectors?
Basically, I need if that style does not contain any css selector, not to display an unnecessary empty code like this:
<style type="text/css" id="compiled_styles">
</style>
Firstly, I think you mean about the existing of some CSS rule in some style, not just selector. You can try this:
var style = document.querySelector('#compiled_styles');
var ss = style.sheet || style.styleSheet;
var hasSomeRule = (ss.rules || ss.cssRules).length;
//remove the style if it's empty
if(!hasSomeRule) (style.parentNode || style.parentElement).removeChild(style);
Demo 1
Another solution is just try getting some text of the style element, if it's not empty it should have some certain rule:
var style = document.querySelector('#compiled_styles');
var hasSomeRule = style.innerHTML.replace(/^\s+$/,'').length;
//remove the style if it's empty
if(!hasSomeRule) (style.parentNode || style.parentElement).removeChild(style);
Demo 2.

Use a remote stylesheet inside a template tag (with shadow dom)

I am trying to make a semi-resuseable widget but I am running into a problem. I am trying to encapsulate a some CSS code inside a shadow root so that it does not affect the rest of the webpage but this CSS is used across multiple widgets so I am trying to include a remote stylesheet. None of the examples I have found use a remote style sheet and I was wondering if this was possible.
EX:
<template id="templateContent">
<head>
<link rel="stylesheet" href="css/generalStyle1.css">
</head>
<body>
<div class="affectedByGeneralStyle1"></div>
</body>
</template>
script to include template:
<div id="host"></div>
<script>
var importedData = (html_import_element).import.getElementById("templateContent");
var shadow = document.querySelector('#host').createShadowRoot();
var clone = document.importNode(importedData.content, true);
shadow.appendChild(clone);
</script>
I came across the same problem recently. What I ended up doing was using:
<template id="templateContent">
<style> #import "css/generalStyle.css"; </style>
</template>
Additional info: This worked just fine except that now I'm having some cache issues as Chrome does not seem to reload those resources after a hard reload.
Let add to the answer . Now direct tag is supported in shadow dom.
You can directly use
<link rel="stylesheet" href="yourcss1.css">
<link href="yourcss2.css" rel="stylesheet" type="text/css">
Check they has been update by whatwg and W3C
Useful link for using css in shadow dom.
https://w3c.github.io/webcomponents/spec/shadow/#inertness-of-html-elements-in-a-shadow-tree https://github.com/whatwg/html/commit/43c57866c2bbc20dc0deb15a721a28cbaad2140c
https://github.com/w3c/webcomponents/issues/628
Direct css link can be use in shadow dom
Thanks.
I added the stylesheet's link element directly to the shadow root this way:
let link = document.createElement('link');
link.setAttribute('rel', 'stylesheet');
link.setAttribute('href', 'whatever.css');
this.shadowRoot.appendChild(link);
It seems to work fine. (I called this from the constructor of the component.)
actually polymer has an internal utility to load css links, i have implemented a javascript function that is using polymer internal css processor,so if you want to add css links at runtime you can use it:
Polymer('my-element', {
ready: function () {
this.importCss("path/myfile.css");
},
importCss: function (path) {
var $shadow = $(this.shadowRoot);
var $head = $("<div></div>");
var $link = $("<link rel='stylesheet' type='text/css'>");
$link.attr("href", path);
$head.append($link);
var head = $head[0];
this.copySheetAttributes = Polymer.api.declaration.styles.copySheetAttributes;
Polymer.api.declaration.styles.convertSheetsToStyles.call(this, head);
var styles = Polymer.api.declaration.styles.findLoadableStyles(head);
if (styles.length) {
var templateUrl = this.baseURI;
Polymer.styleResolver.loadStyles(styles, templateUrl, function () {
var $style = $shadow.find("style");
if ($style.length > 0){
$shadow.find("style").append($head.find("style").html());
}else{
$shadow.append($head.html());
}
});
}
}
});
Note: this code needs jquery to run

Apply css only when text is equal to X

I have a link like this:
<h1>
Title 001 - Stuff
</h1>
I want to style only "Title 001". It's possible to create a css rule to do this?
I don't remember how I did in the past, I think it was something like this:
h1 a[text="Title 001"]
But this doesn't work
And... then I want to know if it possible to do that with "Title XXX" where XXX is a dynamic number.
You can't select by content, but you can use attributes (as you nearly did already).
<h1>
Title 001 - Stuff
</h1>
a[data-content="Title 0001 - Stuff"] {
color: red;
}
Duplicate Content in Attribute
If you would like to avoid using JavaScript, you could duplicate the content (gasp) in an actual attribute, and select based on that attribute:
Title 001 - Stuff
And then select anything that starts with "Title":
a[data-content^="Title"] {
color: red;
}
Manually Test textContent
Alternatively, you'd have to take an approach with JavaScript:
var links = document.querySelectorAll( "a" );
var pattern = /^Title\s\d{3}/;
for ( var i = 0; i < links.length; i++ ) {
if ( pattern.test( links[ i ].textContent ) ) {
links[ i ].classList.add( "distinguish" );
}
}
This is simply one example of how you could add a .distinguish class to all matching elements.
Filtering with jQuery
If you are using jQuery (or a similar utility) you could accomplish this without so much verbosity:
$("a").filter(function () {
return /^Title/.test( $(this).text() );
}).addClass("distinguish");
Isolating "Title :digits:"
If you only want to isolate, and style, the Title XXX portion and you don't have access to the source templates, you could do this too with JavaScript:
$("a").html(function ( index, html ) {
return html.replace(/(Title \d+)/, "<span>$1</span>");
});
The above assumes you are using jQuery, but if you're not you can accomplish the same thing with the following:
var anchors = document.getElementsByTagName("a")
, length = anchors.length
, el;
while ( length-- ) {
el = anchors[ length ];
el.innerHTML = el.innerHTML.replace(/(Title \d+)/, "<span>$1</span>");
}
With css
Title 001 - Stuff
a[data-content^="Title"] {
color: red;
}.
But
Here is what you can do with jQuery in much smarter way,
$('a').filter(function (i, element) {
return element.text == "Title 001 - Stuff";
}).css('color','green');
Working fiddle
I'm afraid this is impossible in CSS.
You're using an attribute selector:
a[text="Title 001"]
and your <a> hasn't got an attribute called text.
You would have to use Javascript to handle such situation. There was once an idea to have a :contains() pseudo-selector but this has never been implemented.

Resources