How to create a print stylesheet which can override the dynamic styles created by css modules ?
Using CSS modules, classnames render with unique names like so :
<button class="buttons_style_primary-button__3T" type="submit"> Submit</button>
In my print stylesheet I have the following, which has no effect :
#media print {
button {
display: none;
}
}
I can get it to work by adding !important to the button style, but I will have many print styles and I don't want to do this for each style attribute. Is there an alternative ?
I'm also using React if there happens to be a React specific approach here.
Wound up doing the following :
Use !important for globals that need to override local values:
/* app.css */
#media print {
#page {
margin: 1cm;
}
* {
color: #000 !important;
}
}
Put component specific overrides into a style.css for each component:
/* style.css */
.my-class {
composes: rounded-corners from 'shared/ui.css';
margin: 0 0 60px 0;
background-color: white;
}
#media print {
.my-class {
page-break-inside: avoid;
font-size: 10px;
}
}
/* my-component.jsx */
import style from './style.css';
const MyComponent = () => {
return (
<div className={style.myClass}>
....
</Link>
);
};
There's also a third option which I haven't really tried.
You should be able to apply both the top-level override classname with your local classname using the classNames library:
import app from 'app.css';
import styles from './style.ss'
const MyComponent = () => {
return (
<div className={classNames(style.local, app.global)}>
....
</Link>
);
};
( this third option is just off the top of my head, I don't know if it will work )
Instead of this:
#media print {
.button {
display: none;
}
}
Try this:
.button{
#media print {
display: none;
}
}
Related
With css-loader
{
test: /\.s?css$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader',
query: {
modules: true,
localIdentName: '[name]-[local]-[hash:base64:8]'
}
},
{ loader: 'sass-loader'}
]
}
configured that way the css-loader seems to not find css rules under class names. The css rules listed under div.profile doesn't get applied on the screen. The css-loader ver. 1.0.0 in my code runs with Node 10.x. Switching modules: false gets the desired styling to show.
The code is posted below.
main.js:
require('babel-runtime/regenerator');
require('babel-register');
require('webpack-hot-middleware/client?reload=true');
require('./index.html');
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Webpack 4</title>
</head>
<body>
<div class="profile">
<img src="./images/400.jpg" alt="">
<h1>Hello Webpack 4</h1>
<div id="react-root"></div>
</div>
<script src="/main-bundle.js"></script>
</body>
</html>
app.js:
import React from 'react';
import ReactDOM from 'react-dom';
import Counter from './counter';
import { AppContainer } from 'react-hot-loader';
const render = (Component) => {
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
document.getElementById('react-root')
);
};
render(Counter);
if (module.hot) {
module.hot.accept('./counter', () => {
render(require('./counter'));
});
}
counter.js:
import React, { Component } from 'react';
import { hot } from 'react-hot-loader';
import { css } from 'emotion';
import styled from 'react-emotion';
import styles from './main.scss';
const Fancy = styled('h1')`
color: ${props => props.wild ? 'hotpink' : 'gold'}
`;
const red = '#f00';
const className = css`
color: ${red};
font-size: 3rem;
`;
class Counter extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
this.addCount = this.addCount.bind(this);
}
addCount() {
this.setState(() => ({ count: this.state.count + 1 }));
}
render() {
const isWild = this.state.count % 2 === 0;
return (
<div className={styles.counter}>
<h1 onClick={this.addCount} className={className}>Count: {this.state.count}</h1>
<Fancy wild={isWild}>react-emotion lib allows to hook styles to component names</Fancy>
</div>
);
}
}
export default hot(module)(Counter);
main.scss:
body {
background-color: #a1b2c3;
}
.profile {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
img {
border-radius: 50%;
box-shadow: 0 0 20px #000;
}
h1 {
font-family: 'source-code-pro', 'sans-serif';
font-weight: 400;
}
}
.counter {
border: 3px solid green;
}
The reason was the .profile class name in index.html is outside the counter.js scope. The css modules produce class names by the localIdentName pattern but the .profile class name was hard coded in index.html before css modules in counter.js came into play.
In counter.js
import styles from './main.scss';
console.log('styles:', styles);
outputs
styles: Object { profile: "main-profile-2P-yNf0J", counter: "main-counter-Pmp5YERO" }
How to get the main-profile-2P-yNf0J class name to index.html remains unclear for me.
I'm trying to add Normalize.css as global and use emotion for my CSS Modules.
First my .babelrc
{
"presets": [
["env", {
"modules": false,
"useBuiltIns": true
}],
"next/babel"
],
"plugins": [
"syntax-dynamic-import",
"transform-runtime",
"transform-decorators-legacy",
"transform-class-properties",
"transform-object-rest-spread",
"es6-promise",
["module-resolver", {
"root": ["./src"],
"alias": {
"styles": "./styles",
"assets": "./assets",
},
"cwd": "babelrc"
}],
["inline-import", { "extensions": [".css"] } ],
["emotion", { "inline": true }]
]
}
Adding Normalize.css
In my _document.js I added the normalize
import Document, { Head, Main, NextScript } from 'next/document';
import normalize from 'normalize.css/normalize.css';
import { extractCritical } from 'emotion-server';
export default class MyDocument extends Document {
static getInitialProps({ renderPage }) {
const page = renderPage();
const styles = extractCritical(page.html);
return { ...page, ...styles };
}
constructor(props) {
super(props);
const { __NEXT_DATA__, ids } = props;
if (ids) {
__NEXT_DATA__.ids = ids;
}
}
render() {
return (
<html>
<Head>
<title>SSR</title>
<style jsx global>{normalize}</style>
<style dangerouslySetInnerHTML={{ __html: this.props.css }} />
</Head>
<body>
<Main />
<NextScript />
</body>
</html>
);
}
}
Same as shown here
Addin my css modules with Emotion
import React, { Component } from 'react';
import Breadcrumb from 'components/Breadcrumb';
import Link from 'next/link';
import styled, { hydrate, keyframes, css, injectGlobal } from 'react-emotion';
// Adds server generated styles to emotion cache.
// '__NEXT_DATA__.ids' is set in '_document.js'
if (typeof window !== 'undefined') {
hydrate(window.__NEXT_DATA__.ids);
}
const basicStyles = css`
background-color: white;
color: cornflowerblue;
margin: 3rem 0;
padding: 1rem 0.5rem;
`
const Basic = styled.div`
${basicStyles};
`
export default class extends Component {
render() {
return (
<Basic>
<p>Basic style rendered by emotion</p>
</Basic>);
}
}
Same as shown here
Problem
Error: StyleSheet: insertRule accepts only strings.
at invariant (/home/riderman/WebstormProjects/tmp/node_modules/styled-jsx/dist/lib/stylesheet.js:274:11)
at StyleSheet.insertRule (/home/riderman/WebstormProjects/tmp/node_modules/styled-jsx/dist/lib/stylesheet.js:125:7)
at /home/riderman/WebstormProjects/tmp/node_modules/styled-jsx/dist/stylesheet-registry.js:88:29
at Array.map (native)
at StyleSheetRegistry.add (/home/riderman/WebstormProjects/tmp/node_modules/styled-jsx/dist/stylesheet-registry.js:87:27)
at JSXStyle.componentWillMount (/home/riderman/WebstormProjects/tmp/node_modules/styled-jsx/dist/style.js:58:26)
at resolve (/home/riderman/WebstormProjects/tmp/node_modules/react-dom/cjs/react-dom-server.node.development.js:2616:12)
at ReactDOMServerRenderer.render (/home/riderman/WebstormProjects/tmp/node_modules/react-dom/cjs/react-dom-server.node.development.js:2746:22)
at ReactDOMServerRenderer.read (/home/riderman/WebstormProjects/tmp/node_modules/react-dom/cjs/react-dom-server.node.development.js:2722:19)
at renderToStaticMarkup (/home/riderman/WebstormProjects/tmp/node_modules/react-dom/cjs/react-dom-server.node.development.js:2991:25)
Added
Check source code here
https://gitlab.com/problems/test-emotion-plus-global-nextjs
Looks like there's an issue for this over on Zeit's styled-jsx page: https://github.com/zeit/styled-jsx/issues/298
According to this issue it is either external styles or that you need to add the css tag to your template literals.
Looking at your code you are using the css tag and don't see any externals styles that would be causing this. If you don't get a definite answer I'd say to follow up on issue 298 with Zeit. HTH, cheers!
Edit
Get rid of the jsx styles in there and just add normalize to your global template string:
injectGlobal`
${normalize}
html, body {
padding: 3rem 1rem;
margin: 0;
background: papayawhip;
min-height: 100%;
font-family: Helvetica, Arial, sans-serif;
font-size: 24px;
}
`;
I have an additional answer to this that works well in TypeScript and NextJS 9. It also keeps your import directly based on your node_modules.
Import raw-loader for the module:
yarn add raw-loader
In a global.d.ts, define a hook for raw-loader
declare module '!!raw-loader!*' {
const contents: string;
export = contents;
}
In a component called Meta I have inside my _document.tsx ( _app.tsx would be fine too, but _document ensures SSR), I have this
import normalizeCss from '!!raw-loader!normalize.css';
const Meta = () => (
<div>
<Global
styles={css`
${normalizeCss}
body {
// ...
}
`}
></Global>
</div>
);
export default Meta;
I have a tab component with two tabs. The buttons are clickable, and clicking on where the buttons should be is correctly displaying the tab contents, but the buttons are invisible.
<ion-header>
<ion-navbar>
<ion-title>{{coupon.title}}</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<div class="coupon-image-container">
<img src={{coupon.mainImage}}/>
<button ion-button class="left">Redeem</button>
</div>
<ion-tabs class="coupon-tabs">
<ion-tab tabIcon="map" [root]="mapTab" tabTitle="Map"></ion-tab>
<ion-tab tabIcon="information" [root]="infoTab" tabTitle="Info"></ion-tab>
</ion-tabs>
</ion-content>
I don't think any other code is necessary but I'll provide more if needed. Like I said the contents of the mapTab and infoTab components are showing up fine, and clicking on where the tab buttons should be is switching between them, but the buttons are just blank white.
Edit: Just in case someone was going to ask, it still does the same thing if I remove everything else in the component except for the tab component like so:
<ion-tabs class="coupon-tabs">
<ion-tab tabIcon="map" [root]="mapTab" tabTitle="Map"></ion-tab>
<ion-tab tabIcon="information" [root]="infoTab" tabTitle="Info"></ion-tab>
</ion-tabs>
So it definitely has nothing to do with the other content.
Edit: I made a gif showing the problem: http://g.recordit.co/WDkjkSz6re.gif
Edit: Here's the styles on ion-tab
element.style {
}
main.css:25224
.coupon-tabs ion-tab {
color: black;
top: 56px;
}
main.css:5136
ion-tab.show-tab {
display: block;
}
main.css:5145
ion-app, ion-nav, ion-tab, ion-tabs, .app-root, .ion-page {
contain: strict;
}
main.css:5132
ion-tab {
display: none;
}
main.css:5128
ion-nav, ion-tab, ion-tabs {
overflow: hidden;
}
main.css:5116
ion-app, ion-nav, ion-tab, ion-tabs, .app-root {
left: 0;
top: 0;
position: absolute;
z-index: 0;
display: block;
width: 100%;
height: 100%;
}
main.css:4986
* {
-webkit-box-sizing: border-box;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
}
Inherited from ion-tabs.coupon-tabs.tabs.tabs-md.tabs-md-primary
main.css:25219
.coupon-tabs {
position: relative;
color: black;
}
main.css:4986
* {
-webkit-box-sizing: border-box;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
}
Look for class .tabbar and check its opacity. Change it if needed.
do this instead:
<ion-tab icon="ion-map" title="Map"></ion-tab>
<ion-tab icon="ion-ios-information" title="Info"></ion-tab>
after you do this you might have noticed that text do not appear, though the text did appear but it was way below the icon and was hidden by overflow. You might need to move the text a bit higher with position: relative; top: -XXpx or make parent overflow: visible.
If you aren't building the project with typescript I guess the issue was tabTitle and tabIcon was not translated properly to the example above or If you we're building this project with typescript then it fails to translate the attributes to its proper way.
hope that helps
I saw some other issues in google related to this
Mine was because i initialised the tabs properties in the top of the class instead of the constructor
This one below doesn't work.
export class TabsPage {
tab1 = Page1;
tab2 = Page2;
constructor() {}
}
This one worked fine.
export class TabsPage {
tab1: any;
tab2: any;
constructor(public navCtrl: NavController, public navParams: NavParams) {
this.tab1 = Page1;
this.tab2 = Page2;
}
}
Also, for some reason tabs were not showing up on the screen, although they were present in the DOM, maybe because i had nested tabs in my app. So had to add this in the tabs-page.scss
.tabbar {
opacity: 1;
}
This is what I have for the grid
#(Html.Kendo().Grid<OPAMvc.Models.Parts>()
.Name("grd")
.Columns(columns =>
{
columns.Bound(o => o.Id).Title("Id No").Width(80).HeaderHtmlAttributes(new { style = "font-size: 8pt; font-weight: bold;" }).HtmlAttributes(new { style = "line-height: 1em;font-size: 7pt;" });
columns.Bound(o => o.Desc).Title("Description").Width(200).HeaderHtmlAttributes(new { style = "font-size: 8pt; font-weight: bold;" }).HtmlAttributes(new { style = "line-height: 1em;font-size: 7pt;" });
columns.Bound(o => o.Price).Title("Price").Width(50).Format("{0:c}").HeaderHtmlAttributes(new { style = "font-size: 8pt; font-weight: bold;" }).HtmlAttributes(new { style = "line-height: 1em;font-size: 7pt;" });
columns.Bound(o => o.Name).Title("Name").Width(20).HeaderHtmlAttributes(new { style = "font-size: 8pt; font-weight: bold;" }).HtmlAttributes(new { style = "line-height: 1em;font-size: 7pt;" });
})
I would like to know if there is a better way to style the header using CSS. Thanks.
There are some kind of methods that I have applied for styling Kendo grid as shown below, but I am not sure if it is helpful for you.
For defining style properties of Kendo grid:
#(Html.Kendo().Grid<Model>()
//define style properties at here
.HtmlAttributes(new { style = "border:none; height:600px;" })
//... code omitted for brevity
)
**For styling individual cells of grid with a template:**
In order to format `Kendo Grid` Column value with conditionally chosen action you can use the example below. For more information: [How Do I Have Conditional Logic in a Column Client Template?](http://docs.telerik.com/kendo-ui/aspnet-mvc/helpers/grid/faq#how-do-i-have-conditional-logic-in-a-column-client-template)
<div id="grid"></div>
<script>
function Getvalue(value) {
// console.log(value);
if (value && value != null && value.indexOf("A") == 0)
return "<b style='color:red'>" + value + "</b>";
else
return "";
}
$(document).ready(function () {
$("#grid").kendoGrid({
dataSource: localDataSource,
columns: [
{
field: "FirstName",
title: "First Name", template: '#=Getvalue(FirstName)#'
}
],
});
});
</script>
the most common way to style a grids header individually is to apply css rules.
try the following
#grd .k-grid-header .k-header
{
font-size: 8pt;
font-weight: bold;
}
this rule will get your "grd" header class and apply the styles
Hi I want to have a dropdown list in my django form with a checkbox in front of every option in the drop down. I have tried using multiple choice field with selectmultiple widget but this displays every option with checkboxes on the page. They are not contained inside the drop down. is there a way to contain them inside the dropdown?
I see that you asked this four years ago so I doubt you are still looking for an answer, but I might as well provide in case someone else finds it!
Basically you want to make a div with an unordered list inside of it, where each item in that list contains a checkbox input.
Then, you use jQuery so that when you click on the div, it gets assigned the 'selected' class in its html.
Then you make your CSS so that the dropdown menu itself only shows up when it has the 'selected' class.
The JSFiddle is here (minus the django templating, obviously):
https://jsfiddle.net/lymanjohnson/2L71nhko/15/
And code is below:
HTML (django template):
<fieldset class="item toggle-item">
<div class="legend-container">
<legend>Choices</legend>
</div>
<ul class="scrollable-dropdown-list">
{% for choice in choices %}
<li>
<input type="checkbox" class="custom-control-input filter" id="choice_{{forloop.counter}}" name="choice" value="{{choice}}">
<label for="choice_{{forloop.counter}}"class="custom-control-label">{{choice}}</label>
</li>
{% endfor %}
</ul>
</fieldset>
JQUERY:
<script>
$(document).ready(function() {
// Listener for when you click on the dropdown menu
$('fieldset.toggle-item > .legend-container').on('click', (event) => {
// Adds or removes the 'selected' attribute on the dropdown menu you clicked
$(event.currentTarget).parent().toggleClass('selected')
// If you have multiple dropdown menus you may want it so that when you open Menu B, Menu A
// automatically closes.
// This line does that by removing 'selected' from every dropdown menu other than the one you clicked on.
// It's 'optional' but it definitely feels better if you have it
$('fieldset.toggle-item').not($(event.currentTarget).parent()).removeClass('selected')
})
// The user is probably going to expect that any and all dropdown menus will close if they click outside of them. Here's how to make that happen:
//This listens for whenever you let go of the mouse
$(document).mouseup(function(e)
{
// make this a variable just to make the next line a little easier to read
// a 'container' is now any
var dropdown_menus = $("fieldset.toggle-item");
// if the target of the click isn't a dropdown menu OR any of the elements inside one of them
if (!dropdown_menus.is(e.target) && dropdown_menus.has(e.target).length === 0)
{
// then it will de-select (thereby closing) all the dropdown menus on the page
$('fieldset.toggle-item').removeClass('selected')
}
});
})
</script>
CSS:
<style>
.item {
width: 33%;
margin: 2px 1% 2px 1%;
border: 0;
}
.item li {
list-style: none;
}
.scrollable-dropdown-list{
position: absolute;
max-height:200px;
width:33%;
overflow-y:scroll;
overflow-x:auto;
margin: 0;
padding-left: 1em;
border-style: solid;
border-width: thin;
border-color: grey;
background-color: white;
}
legend {
margin-bottom: 0;
font-size: 18px;
}
label {
font-weight: normal;
margin-left:20px;
}
.legend-container {
cursor: pointer;
width: 100%;
display: flex;
padding: 0;
margin-bottom: 0px;
font-size: 21px;
line-height: inherit;
color: #333;
border: 0;
border-bottom: none;
}
fieldset {
border-width: thin;
border-color: gray;
border-style: solid;
width:50px;
}
/* Note that all the browser-specific animation stuff is totally optional, but provides a nice subtle animation for the dropdown effect */
fieldset ul.scrollable-dropdown-list {
display: none;
-webkit-animation: slide-down .3s ease-out;
-moz-animation: slide-down .3s ease-out;
}
fieldset.selected ul.scrollable-dropdown-list {
display: block;
-webkit-animation: slide-down .3s ease-out;
-moz-animation: slide-down .3s ease-out;
}
#-webkit-keyframes slide-down {
0% {
opacity: 0;
-webkit-transform: translateY(-10%);
}
100% {
opacity: 1;
-webkit-transform: translateY(0);
}
}
#-moz-keyframes slide-down {
0% {
opacity: 0;
-moz-transform: translateY(-10%);
}
100% {
opacity: 1;
-moz-transform: translateY(0);
}
}
</style>
Dropdowns and checkboxes are HTML elements that are rendered by the browser using its built-in components. Those components don't have any support for combining them: in pure HTML, you simply can't combine a select with a check box.
The only way to do this would be to use components rendered purely in Javascript. Google's Closure UI tools is one set of controls I've used, but only because I used to work at Google: something like jQuery UI might have a version that's easier to use.